Echte Zufallszahl erzeugen?

#1986226
Lesenswert?

Hallo,
mein Programm mag nach
1
#include <time.h>
2

3
srand(time(0));
mit
1
int zahl=rand();
immernoch keine immer unterschiedlichen Zufallszahlen ausspucken. Bei 
häufigem Aufrufen von rand() scheint es sich auch aufzuhängen. Ich weiß, 
dass auch nach srand immer nur etwa jede Sekunde eine "neue" Zahl 
möglich ist. Im Debugger läuft deshalb auch alles problemlos, denn da 
sind ja die Zeitabstände wesentlich größer und das Programm hängt sich 
auch nicht auf.
Aber wie macht man denn nun eine "echte" Zufallszahl, auch wenn es das 
beim Computer nicht gibt?
#1986267
Lesenswert?

Mark M. schrieb:
> Bei
> häufigem Aufrufen von rand() scheint es sich auch aufzuhängen. Ich weiß,
> dass auch nach srand immer nur etwa jede Sekunde eine "neue" Zahl
> möglich ist. Im Debugger läuft deshalb auch alles problemlos, denn da
> sind ja die Zeitabstände wesentlich größer und das Programm hängt sich
> auch nicht auf.

Bei meinem selbstgeproggten Spielen verwende ich immer rand() und es 
hängt sich nie auf. Es wird auch z.T mehrere hundert mal in der Sekunde 
aufgerufen. Da wird wohl eher ein Fehler in deinem Programm sein.
#1986275
Lesenswert?

Mark M. schrieb:
> mit
> int zahl=rand();
> immernoch keine immer unterschiedlichen Zufallszahlen ausspucken.

[...]

> Bei häufigem Aufrufen von rand() scheint es sich auch aufzuhängen.

Das rand() deiner C-Bilbiothek scheint ziemlich kaputt zu sein, oder 
dein Programm enthält einen Fehler.

> Ich weiß, dass auch nach srand immer nur etwa jede Sekunde eine "neue"
> Zahl möglich ist.

Wie kommst du denn darauf?

> Im Debugger läuft deshalb auch alles problemlos, denn da sind ja die
> Zeitabstände wesentlich größer und das Programm hängt sich auch nicht
> auf.

Es gibt jede Menge möglicher Gründe, warum sich das Programm im Debugger 
nicht aufhängt. Die Zeitabstände zwischen Aufrufen von rand() gehören da 
aber eher nicht dazu.

> Aber wie macht man denn nun eine "echte" Zufallszahl, auch wenn es das
> beim Computer nicht gibt?

Erstmal solltest du rausfinden, warum rand() bei dir nicht funktioniert. 
Wozu brauchst du denn eine echte Zufallszahl? Es gibt manche Computer, 
die einen Hardware-Zufallszahlengenerator eingebaut haben, der den Wert 
z.B. über das termische Rauschen eines Transistors ermittelt.
Gast #1986289
Lesenswert?

Aus deiner Aussage "immer unterschiedliche Zahlen" entnehme ich, das du 
vielleicht eine Liste mir Liedern abspielen willst und sich kein Lied 
wiederholen soll oder sowas ähnliches. Also erstmal ist es bei 
zufälligen Zahlen auf keinen Fall so, dass sie sich nciht wiederholen. 
Das die Zahlen gleichverteilt sind, gilt nur für unendlich viele Aufrufe 
der Funktion. Und da es Pseudozufallszahlen stimmt auch das mit der 
Gleichverteilung nur bedingt.
Wenn du wirklich eine Playliste oder sowas in der Art machen willst, 
dann schreibe die die Titel bzw. die Zahlen von z.B. 1 bis 100 in eine 
Liste. Dann sortierst du die Liste um, indem du zufällig zwei Elemente 
tauschst. Also so in der Art:

for (i = 0; i < 100; i++)
{
  int idx1 = rand() % 100;
  int idx2 = rand() % 100;

  int sp = liste[idx1];
  liste[idx1] = liste[idx2];
  liste[idx2] = sp;
}
#1986371
Lesenswert?

Wie benutzt Du die beiden Funktionen?
Wichtig ist daßß man den Pseudozufalsszahlengenerator EIN mal 
initialisiert
z.B. mit

time_t t;
time(&t);
srand((unsigned int)t);

danach kann man die Funktion so oft benutzen wie man will!
Wichtig: Mit dem selben Startwert bekommt amn immer die identische 
Zufallszahlenfolge, es ist halt ein Pseudozufallsgenerator, aber die 
Folge an sich ist relativ gut verteilt!
Deshalb muss man den Generator auch bei jedem Start durch eine neue Zahl 
(z.B Zeit) neu initialisieren.
#1986392
Lesenswert?

Wenn mich meine eingerosteten C kenntnisse nicht täuschen sollte man 
beim Aufruf von time korrekterweise nicht time(0); sondern time(NULL); 
benutzen, um kenntlich zu machen, daß ein Zeiger übergeben wird (bzw 
halt der NULL Pointer)
Ausserdem sollte das entsprechende include nicht fehlen.
Ich glaube für die Zufallszahlen ist das stdlib.h.
#1986484
Lesenswert?

Udo Schmitt schrieb:
> Wenn mich meine eingerosteten C kenntnisse nicht täuschen sollte man
> beim Aufruf von time korrekterweise nicht time(0); sondern time(NULL);
> benutzen, um kenntlich zu machen, daß ein Zeiger übergeben wird (bzw
> halt der NULL Pointer)

Psst.
NULL ist nichts anderes als eine Verpackung für 0
Und zwar für den Integer 0!
Und keinesfalls für einen void Pointer

(Übrigens sehr zu meinem Leidwesen)
Gast #1986659
Lesenswert?

Ein schöner Algorithmus, um eine Zufallszahl zu erzeugen:

unsigned int m_z;
unsigned int m_w;

void InitRandomNumber(void)
{
  m_w = 521288629;
  m_z = 362436069;
}

USHORT GetRandomNumber(void)
{
  m_z = 36969 * (m_z & 65535) + (m_z >> 16);
  m_w = 18000 * (m_w & 65535) + (m_w >> 16);

  return(USHORT)(((m_z << 16) + m_w) & 0x0000ffff);
}

Ich habe hier auf USHORT gecastet, weil ich nur 16-Bit Zahlen gebraucht 
habe. Kannst Du ja entsprechend anpassen. Der Algorithmus erzeugt 
zumindest "bessere" Zufallszahlen als rand().
#1986692
Lesenswert?

Frank schrieb:
> Ein schöner Algorithmus, um eine Zufallszahl zu erzeugen:

Wo hast du ihn her?

> habe. Kannst Du ja entsprechend anpassen. Der Algorithmus erzeugt
> zumindest "bessere" Zufallszahlen als rand().

Kommt immer drauf an, was man unter besser versteht.
Zufallszahlen sind statistisch gar nicht so leicht zu fassen. Aussagen 
über die Qualität eines Generators kann man aber nur auf statistischer 
Basis erhalten.
Gast #1986722
Lesenswert?

@ Karl heinz Buchegger

http://en.wikipedia.org/wiki/Random_number_generation

http://www.codeproject.com/KB/recipes/SimpleRNG.aspx?msg=3459566

und weitere 24000 Links in Google.

Irgendwann habe ich auch einmal eine umfassende Abhandlung über diesen 
Algorithmus im Internet gelesen - finde ich auf die Schnelle aber nicht 
mehr.
Es wurde aber gezeigt, dass die Zahlen zufälliger sind, als mittels 
rand() erzeugt.
Gast #1986725
Lesenswert?

>Mach' Dich zunächst im
>Internet über diesen Algorithmus schlau.

Warum sollte ich das tun?

Du gibst keine Referenz an, bezeichnest ihn als "zumindest "bessere" 
Zufallszahlen als rand()". Wobei ich kaum glaube, das jede (C) rand() 
Implementierung identisch ist.

Generierung von Zufallszahlen ist eine komplizierte Wissenschaft, soviel 
weiß ich immerhin, und das genügt mir derzeit.
Gast #1986743
Lesenswert?

Es kommt immer darauf an, zu was man die Zufallszahl braucht - für ein 
Spiel reicht eine einfache SW Generierung sicher aus. Aber wenn es um 
Krypto und Security geht, dann sieht die Sache wieder ganz anders aus, 
da kriegt man ganz schnell seine so wunderbar ausgeklügelte, 
selbstgebastelte Lösung ganz schnell um die Ohren gehauen...
(Nicht umsonst hat ST seiner neuen F2x Controller Reihe nun einen in 
Hardware gegossenen analogen Zufallszahlengenerator spendiert.)
#1986757
Lesenswert?

Karl heinz Buchegger schrieb:
> Psst.
> NULL ist nichts anderes als eine Verpackung für 0
> Und zwar für den Integer 0!
> Und keinesfalls für einen void Pointer
Wie gesagt, die Kenntnisse sind etwas angerostet. Trotzdem weisst einem 
das NULL darauf hin daß es ein Pointer sein soll und kein int.
K&R sagt dazu: "Die symbolische Konstante NULL wird benutzt um 
hervorzuheben, daß dies ein spezieller Wert für einen Zeiger ist".
Obwohl, soweit ich mich erinnere NULL nicht immer als ((void *)0) 
definiert ist, sondern auch manchmal einfach als 0.

Karl heinz Buchegger schrieb:
> Jede Wette es funktioniert perfekt.
> Nur hat ihm keiner erzählt, dass man srand() nur EINMAL aufruft und dann
> lässt man den Generator in Ruhe seinen Job machen:
Doch, hatte ich 2 Postings vorher schon gemacht :-)
Schöne Weihnachten
Udo
#1986824
Lesenswert?

Frank schrieb:
> @ Karl heinz Buchegger
>
> http://en.wikipedia.org/wiki/Random_number_generation

Danke für die Links.
Aber ich weiß schon was es mit Zufallszahlen auf sich hat und auch wo 
die Probleme liegen.


> Es wurde aber gezeigt, dass die Zahlen zufälliger sind, als mittels
> rand() erzeugt.

Aha.
Da der C-Standard einem Entwickler nicht vorschreibt, welchen Generator 
er zu benutzen hat, ... woher weißt du, dass in der Runtime-Lib des 
Fragestellers nicht gerade dieses Verfahren benutzt wird?

Aber es stimmt schon.
Frühere rand() Implementierungen waren meistens nicht besonders gut. 
Daher wurde oft von der üblichen Methode

      a = rand() % Maximum

abgeraten, weil man wusste, dass die 'kleinen' Bits kein gutes 
statistisches Zufallsverhalten zeigten.

Für den Hausgebrauch gut genug. Für Ca*sinos allerdings zu schwach.
Allerdings sind einige Aussagen des Fragestellers dergestalt, dass die 
methodischen Probleme von rand() eher nicht zu seinen Problemen zählen 
dürften.
Gast #1986854
Lesenswert?

@ Karl heinz Buchegger

Da gebe ich Dir freundlicherweise einen Link über die 
Multiply-with-carry Methode des Mathematikers George Marsaglia. Und 
Deine Antwort ist: Aber ich weiß schon was es mit Zufallszahlen auf sich 
hat und auch wo
die Probleme liegen. (???)

Da gebe ich Hilfestellung und poste einen Algorithmus, der allgemein 
unter Softwerkern, die sich mit Zufallszahlen beschäftigen, bekannt sein 
sollte. Und ich soll mich auch noch dafür rechtfertigen?
#1986919
Lesenswert?

Frank schrieb:
> @ Karl heinz Buchegger
>
> Da gebe ich Dir freundlicherweise einen Link über die
> Multiply-with-carry Methode des Mathematikers George Marsaglia. Und
> Deine Antwort ist: Aber ich weiß schon was es mit Zufallszahlen auf sich
> hat und auch wo
> die Probleme liegen. (???)
>
> Da gebe ich Hilfestellung und poste einen Algorithmus, der allgemein
> unter Softwerkern, die sich mit Zufallszahlen beschäftigen, bekannt sein
> sollte. Und ich soll mich auch noch dafür rechtfertigen?#

Nein, du sollst dich nicht dafür rechtfertigen.
Du sollst überlegen, inwiefern dein Generator das Problem des 
Fargestellers lösen kann.
Seni Problem ist sicher nicht die mangelnde Qualität von rand() (über 
die man debattieren kann). Sein Problem ist, dass er rand() offenbar 
nicht richtig benutzen kann!
#1987152
Lesenswert?

Mark M. schrieb:

> Aber wie macht man denn nun eine "echte" Zufallszahl, auch wenn es das
> beim Computer nicht gibt?

Die üblichen Software-Implementierungen erzeugen deterministische 
Zahlenfolgen, was für mancherlei Anwendungen ausreicht, aber für 
kryptographische Verfahren allenfalls, wenn der Startwert gut zufällig 
ist (die beliebte Uhrzeit ist es nicht).

Echt wird es, indem physikalische Vorgänge zufälligen Charakters 
gemessen werden, wie Rauschen. Trivial ist das aber nicht unbedingt, 
denn man sollte schon sicher sein, dass man es wirklich mit zufälligem 
Rauschen zu tun hat und nicht mit irgendwelchen Störsignalen.

Dem annähern kann man sich, indem man diverse nicht miteinander 
korrelierte Faktoren zusammenführt, wie irgendwelche Daten und 
Wartezeiten aus Device Drivern und interaktiven Aktionen. In Linux 
findet man das in /dev/random.
Gast #1987181
Lesenswert?

> Aber wie macht man denn nun eine "echte" Zufallszahl, auch wenn es das
> beim Computer nicht gibt?
TrueCrypt erzeugt den Schlüssel (aus Zufallszahlen) unter Anderem mit 
Hilfe der Benutzereingaben. Der Benutzer muss möglichst lange seine Maus 
bewegen und verändert mit jedem Bewegungsschritt den Schlüssel. Je 
nachdem, was der Benutzer mit der Maus macht, ist das ziemlich 
'zufällig'.
#1987349
Lesenswert?

Rolf Magnus schrieb:
>> Ich weiß, dass auch nach srand immer nur etwa jede Sekunde eine "neue"
>> Zahl möglich ist.
>
> Wie kommst du denn darauf?

Hier Beitrag "zufallszahl mit rand() erzeugen" steht:
Rolf Magnus schrieb:
>>Das Problem ist, dass bei jedem Aufruf der Funktion der gleiche
>> zufallswert erzeugt wird und ich benötige unterschiedliche Werte
>
> Vermutlich nicht bei jedem Aufruf, sondern immer genau eine Sekunde lang
> bzw bis time() einen neuen Wert liefert.

Das ist auch mein Problem. Wenn ich die Funktion in ner while-Schleife 
mehrmals durchlaufen lasse, kommt mehrmals direkt hintereinander das 
gleiche. Wenn ich dazwischen andere Aktionen packe, dann nicht.
Ich hab zum Bespiel die Eingabe einer beliebigen Taste dazwischen 
gemacht, das läuft auch, hängt sich aber eben nach dem 4., 5. mal auf.
1
struct vokabel vokabel_aus_datei(char datei[])
2
{
3
    int zeilenzahl=zeilen(datei);            // zeilenzahl/7==anzahl vokabeln
4
    srand(time(0));
5
    int nummer=0;
6
    do
7
    {
8
         nummer=rand()%(zeilenzahl/7); // nummer==zahl zwischen 0 und anzahl_vokabeln-1
9
    } while(vorigeChk(nummer)==1);
10

11
    int zeilennummer=nummer*7+1; // zeilennummer, ab der die Vokabel steht
12

13
    vorigeApp(nummer); // Zufallszahl speichern, damit sie nicht mehr so schnell vorkommt
14

15
    FILE* stream;
16
    stream=fopen(datei,"r");
17
    fseek(stream,0,SEEK_SET);  // an den Anfang springen
18
    long int cntln=0; // zählt die Zeilen
19
    char zeichen=fgetc(stream);
20
    while(zeichen!=EOF)
21
    {
22
        if(zeichen=='\n') cntln++;
23
        if(cntln==zeilennummer) break; // zufälliges Wort gefunden, Zeiger steht vor diesem
24
        zeichen=fgetc(stream);
25
    } // am Ende steht der Zeiger vor dem gesuchten Wort
26

27
    long int akt_pos=ftell(stream)-2;
28
    fclose(stream);
29

30
    struct vokabel neu; // neue Vokabel angelegt, sie wird im Folgenden beschrieben
31
    int lesen=0;
32
    while(lesen<8)
33
    {
34
        long int cntch=cntcharacter(datei,akt_pos); // Zeichen zählen
35

36
        stream=fopen(datei,"r");
37
        fseek(stream,akt_pos,SEEK_SET);
38
        switch(lesen)
39
        {
40
            case 0: break;
41
            case 1: fgets(neu.wort,cntch,stream);  
42
            break;
43
            case 2: fgets(neu.bed_1,cntch,stream);
44
            break;
45
            case 3: fgets(neu.bed_2,cntch,stream);
46
            break;
47
            case 4: fgets(neu.bed_3,cntch,stream);
48
            break;
49
            case 5: fgets(neu.bed_4,cntch,stream);
50
            break;
51
            case 6: fgets(neu.bed_5,cntch,stream);
52
            break;
53
            case 7: break;
54
            default: fehler("beim Einlesen von Datei in struct!");
55
        }
56
        fclose(stream);
57
        lesen++;
58
        akt_pos=akt_pos+cntch+1; // 1 für den Zeilenumbruch
59
    }
60

61
    return neu;
62
}
Gast #1987388
Lesenswert?

Wie Karl heinz Buchegger schon gestern (22.12.2010 15:52) schrieb:

srand NUR einmal am Anfang vom Programm aufrufen.

rand() ermittelt den neuen Wert aus dem letzten Zufallswert.
Wenn du mit srand() jedes mal den  Startwert für rand() neu setzt kann 
das nichts werden.

Dann musst du den Rückgabewert von fopen auch prüfen ob es geklappt hat.

Ein Aufruf von fopen in der Funktion sollte auch reichen.
#1987430
Lesenswert?

Nachdem die Sache mit dem srand (nur EIN Aufruf am Programmstart) jetzt 
geklärt ist: Was hast du hier eigentlich vor?
1
struct vokabel vokabel_aus_datei(char datei[])
2
{
3
    int zeilenzahl=zeilen(datei);            // zeilenzahl/7==anzahl vokabeln
4
    srand(time(0));
5
    int nummer=0;
6
    do
7
    {
8
         nummer=rand()%(zeilenzahl/7); // nummer==zahl zwischen 0 und anzahl_vokabeln-1
9
    } while(vorigeChk(nummer)==1);
10

11
    int zeilennummer=nummer*7+1; // zeilennummer, ab der die Vokabel steht

Wenn du eien Sequenz von Zahlen in einem bestimmten Bereich benötigst, 
von denen garantiert keine doppelt vorkommt und die bunt durcheinander 
gewürfelt sind, dann macht man das so:

Man erzeugt sich ein Array mit den Zahlen von 0 bis zur Obergrenze

  for( i = 0; i < ANZAHL; ++i )
    arr[i] = i;

und dann würfelt man die durcheinander, indem man zufällig immer 2 
Elemente vertauscht

  for( i = 0; i < ANZAHL; ++i ) {
    randInd = rand() % ANZAHL;
    tmp = arr[i];
    arr[i] = arr[randInd];
    arr[randInd] = tmp;
  }

und erhält dann ein Array mit der gewünschten Länge, in der die Zahlen 
von 0 bis ANZAHL-1 in einer zufälligen Reihenfolge angeordnet sind.
Man braucht dann nur noch 1 Element nach dem nächsten sich dort abholen 
und kann das dann zb zur Auswahl der nächsten Vokabel benutzen.
#1987432
Lesenswert?

Mark M. schrieb:
> DirkB schrieb:
>> srand NUR einmal am Anfang vom Programm aufrufen.
>
> Wenn ich das mache, hängt er sich auf.

Wo genau?
Wahrscheinlich hier
1
    do
2
    {
3
         nummer=rand()%(zeilenzahl/7); // nummer==zahl zwischen 0 und anzahl_vokabeln-1
4
    } while(vorigeChk(nummer)==1);

wenn du prüfst ob diese Zahl schon vorgekommen ist.
Zeig doch mal den Mechanismus der da dahinter steckt oder schmeiss ihn 
gleich über Board. Wenn du die Sache mit dem srand korrigiert hast, 
brauchst du ihn nicht mehr (ist ja nicht schlimm, wenn ab und zu 
dieselbe Vokabel 2 mal hintereinander abgefragt wird. Das wird nicht 
sehr oft vorkommen, sobald du srand() richtig einsetzt)
#1987434
Lesenswert?

Mark M. schrieb:
> DirkB schrieb:
>> srand NUR einmal am Anfang vom Programm aufrufen.
>
> Wenn ich das mache, hängt er sich auf.
>
> DirkB schrieb:
>> Ein Aufruf von fopen in der Funktion sollte auch reichen.
>
> Sicher? In
>
1
long int cntcharacter(FILE* datei, long int akt_pos);
 wird die
> Datei aber auch gelesen. Kann ich den Stream dann wie ein Zeiger
> übergeben?


Du liest mir ehrlich gesagt etwas zuviel von den Dateien ein.

Gibt es einen Grund, warum du den Vokabelvorrat nicht einfach im 
Speicher halten willst?

Wenn eine Vokabel dazukommt, wird sofort alles auf die Datei gesichert, 
aber ansonsten wird alles im Speicher abgewickelt.
#1987440
Lesenswert?

Ja, definitiv.
Du hast dich da mächtig verrant.
1
   int lesen=0;
2
    while(lesen<8)
3
    {
4
        long int cntch=cntcharacter(datei,akt_pos); // Zeichen zählen
5

6
        stream=fopen(datei,"r");
7
        fseek(stream,akt_pos,SEEK_SET);
8
        switch(lesen)
9
        {
10
            case 0: break;
11
            case 1: fgets(neu.wort,cntch,stream);  
12
            break;
13
            case 2: fgets(neu.bed_1,cntch,stream);
14
            break;
15
            case 3: fgets(neu.bed_2,cntch,stream);
16
            break;
17
            case 4: fgets(neu.bed_3,cntch,stream);
18
            break;
19
            case 5: fgets(neu.bed_4,cntch,stream);
20
            break;
21
            case 6: fgets(neu.bed_5,cntch,stream);
22
            break;
23
            case 7: break;
24
            default: fehler("beim Einlesen von Datei in struct!");
25
        }
26
        fclose(stream);
27
        lesen++;
28
        akt_pos=akt_pos+cntch+1; // 1 für den Zeilenumbruch
29
    }

das alles ist hauptsächlich eines:
maximale Beschäftigungstherapie für Rechner und Festplatte.

aber ansonsten ziemlich sinnlos und maximal kompliziert
1
    FILE* stream;
2
    stream=fopen(datei,"r");
3
    fseek(stream,0,SEEK_SET);  // an den Anfang springen
wenn du eine Datei zum Lesen öffnest, steht der Filepointer sowieso am 
Anfang. Da musst du nicht extra hinseeken

1
    long int cntln=0; // zählt die Zeilen
2
    char zeichen=fgetc(stream);
3
    while(zeichen!=EOF)
4
    {
5
        if(zeichen=='\n') cntln++;
6
        if(cntln==zeilennummer) break; // zufälliges Wort gefunden, Zeiger steht vor diesem
7
        zeichen=fgetc(stream);
8
    } // am Ende steht der Zeiger vor dem gesuchten Wort
kann man so machen. Aber wozu? fgets liest perfekt eine Zeile. Wenn du 
bis zur i-ten Zeile nach vorne willst, dann lies einfach i Zeilen 
mittels fgets ein

1
    long cntln = 0;
2

3
    while( cntln < zeilennummer && fgets( dummy, sizeof( dummy ), stream ) )
4
      cntln++;

jetzt steht der FilePointer am Anfang der gewünschten Zeile, und da 
jetzt einfach 7 Zeilen lesen
1
    fgets( neu.wort, sizeof(neu.wort), stream );
2
    fgets( neu.bed_1, sizeof(neu.bed1), stream );
3
    fgets( neu.bed_2, sizeof(neu.bed2), stream );
4
    fgets( neu.bed_3, sizeof(neu.bed3), stream );
5
    fgets( neu.bed_4, sizeof(neu.bed4), stream );
6
    fgets( neu.bed_5, sizeof(neu.bed5), stream );

Fertig. (Die gelesenen \n am Stringende müsste man eventuell noch 
entfernen)

Dir scheint auch nicht klar zu sein, welche Bedeutung der 2. Parameter 
von fgets hat.
Das ist nicht die Anzahl der Zeichen, die du zu lesen gedenkst, sondern 
die Größe des Buffers, den du fgets zum Lesen übergibst! Du musst daher 
nicht vorher feststellen, wie lang eine Zeile überhaupt ist. Das wäre 
ziemlich sinnlos, wenn dich fgets dazu zwingen würde. fgets liest von 
sich aus bis zum Zeilenende. Aber: wie bei allen Funktionen, die einen 
String in einen Buffer schreiben, wäre es tunlichst angeraten, wenn 
nicht zuviele Zeichen in diesen Buffer geschrieben werden und diesen 
überlaufen. Daher muss fgets wissen, wie gross der Buffer ist. Das ist 
dann auch gleichzeitig die maximale Anzahl an Zeichen, die fgets 
gefahrlos lesen darf.
1
    fclose(stream);

Das passt wieder.

Den Rückgabewert von fopen musst du noch testen!


Und so sieht das dann in Summe aus:
1
    FILE* stream;
2
    stream = fopen( datei,"r" );
3

4
    long cntln = 0;
5

6
    while( cntln < zeilennummer && fgets( dummy, sizeof( dummy ), stream ) )
7
      cntln++;
8

9
    fgets( neu.wort, sizeof(neu.wort), stream );
10
    fgets( neu.bed_1, sizeof(neu.bed1), stream );
11
    fgets( neu.bed_2, sizeof(neu.bed2), stream );
12
    fgets( neu.bed_3, sizeof(neu.bed3), stream );
13
    fgets( neu.bed_4, sizeof(neu.bed4), stream );
14
    fgets( neu.bed_5, sizeof(neu.bed5), stream );
15

16
    fclose(stream);



PS:
Wieso eigentlich 7?
Eine Vokabelbeschreibung besteht bei dir aus 6 Zeilen!
#1987558
Lesenswert?

Karl heinz Buchegger schrieb:
> PS:
> Wieso eigentlich 7?
> Eine Vokabelbeschreibung besteht bei dir aus 6 Zeilen!

Weil ich zwischen jeder Vokabel eine Leerzeile habe, damit es 
übersichtlich bleibt, wenn man die Datei von Hand erweitert.

Karl heinz Buchegger schrieb:
> Was hast du hier eigentlich vor?
> struct vokabel vokabel_aus_datei(char datei[])
> {
>     int zeilenzahl=zeilen(datei);            // zeilenzahl/7==anzahl vokabeln
>     srand(time(0));
>     int nummer=0;
>     do
>     {
>          nummer=rand()%(zeilenzahl/7); // nummer==zahl zwischen 0 und 
anzahl_vokabeln-1
>     } while(vorigeChk(nummer)==1);
>
>     int zeilennummer=nummer*7+1; // zeilennummer, ab der die Vokabel steht

Der Check ist wahrscheinlich etwas umständlich impplementiert. 
zeilennummer soll aber danach genau die Zahl haben, ab der das 
fremdsprachige Wort steht, und das muss eine durch 7 teilbare Zahl sein 
(mit einem "Offset" von 1, weil am Anfang der Datei auch eine Leerzeile 
steht).
#1988587
Lesenswert?

Schauen wir doch mal in die Sprachdefinitionen:

C:
1
An integer constant expression with the value 0, or such an expression cast to type
2
void *, is called a null pointer constant.

C++:
1
A null pointer constant is an integral constant expression rvalue of integer type that evaluates to
2
zero.

In beiden Sprachen muß NULL natürlich eine null pointer constant sein.
#1988617
Lesenswert?

Rolf Magnus schrieb:
> ... die Sprachdefinitionen ...

Schön, daß es nur je eine gibt für C und C++  :-)


Ich denke, da liegt einfach der Hund begraben.
Alleine für C gibt es soviele Varianten, daß man jahrelang sinnlos
streiten kann, wie es denn in C definiert sei, solange sich niemand
äußert, auf welche Version er sich denn nun beziehen mag.
C als solches gibt es nicht, wenn man Korinthenkackerei betreiben will.

Abgesehen davon, daß es wichtigeres gibt, ob man 0 als 0 schreibt,
oder 1-1.

Frohe Weihnachten, egal ob mit void* oder int - jeder wie er will!
#1988629
Lesenswert?

Klaus Wachtler schrieb:
> Rolf Magnus schrieb:
>> ... die Sprachdefinitionen ...
>
> Schön, daß es nur je eine gibt für C und C++  :-)

Es gibt tatsächlich nur je eine.

> Ich denke, da liegt einfach der Hund begraben.
> Alleine für C gibt es soviele Varianten, daß man jahrelang sinnlos
> streiten, wie es denn in C definiert, solange sich niemand äußert,
> auf welche Version er sich denn nun beziehen mag.

Es gibt halt verschiedene Compiler, die sich mehr oder weniger gut an 
die Spezifikation halten. Und es gibt natürlich alten Code, der noch aus 
der Zeit davor stammt.

> C als solches gibt es nicht, wenn man Korinthenkackerei betreiben will.

Doch. Es ist definiert in ISO/IEC 9899:1999, wo ich auch den zitierten 
Satz her habe.

> Abgesehen davon, daß es wichtigeres gibt, ob man 0 als 0 schreibt,
> oder 1-1.

Das sicherlich. Ob NULL nun 0 oder (void*)0 ist, spielt in der Praxis an 
sich auch keine Rolle. Bei manchen Compilern mag letzteres von Vorteil 
sein, weil man dann eine Warnung bekommt, wenn man es versehentlich im 
Kontext von Integern verwendet.


> Frohe Weihnachten, egal ob mit void* oder int - jeder wie er will!

Ebenso.
Gast #1989261
Lesenswert?

Klaus Wachtler schrieb:
> Trägt das jetzt irgendwie zu (void*) oder int bei?

Ja. Es ist ein direkter Widerspruch zu deiner falschen Behauptung.

> Kümmert das jemanden?

Mich. Und jeden, der sich für die Sprache C interessiert und das Makro 
NULL sowie Nullpointer verstehen will.

Aber pfusche du ruhig auf Basis von "ich hab da mal mal gesehen" 
weiter...
#1989352
Lesenswert?

Um nochmal kurz zurück zum Thema zu kommen:

Karl heinz Buchegger schrieb:
> Wenn du eien Sequenz von Zahlen in einem bestimmten Bereich benötigst,
> von denen garantiert keine doppelt vorkommt und die bunt durcheinander
> gewürfelt sind, dann macht man das so:
>
> Man erzeugt sich ein Array mit den Zahlen von 0 bis zur Obergrenze
>
>   for( i = 0; i < ANZAHL; ++i )
>     arr[i] = i;
>
> und dann würfelt man die durcheinander, indem man zufällig immer 2
> Elemente vertauscht

Hat jemand eine Idee, wie man das ohne ein solches Array hinbekommen 
kann?
Bevor die offensichtliche Gegenfrage kommt: In meinem Fall wäre dieses 
Array 32 GB groß, und soviel RAM habe ich nicht.
Gast #1989370
Lesenswert?

> Hat jemand eine Idee, wie man das ohne ein
> solches Array hinbekommen kann?

Mit einem genügend grossen LFSR? Kommt aber wohl darauf an, was du sonst 
noch für Ansprüche an die generierte Sequenz hast.
#1989406
Lesenswert?

Bartli schrieb:
>> Hat jemand eine Idee, wie man das ohne ein
>> solches Array hinbekommen kann?
>
> Mit einem genügend grossen LFSR? Kommt aber wohl darauf an, was du sonst
> noch für Ansprüche an die generierte Sequenz hast.

Ich habe einen Wertebereich von 0 bis n (n variabel, grob im Bereich 
einige Millionen bis mehrere Milliarden - 32 Bit reichen notfalls, 64 
wären aber besser) und hätte nun gerne eine C-Funktion, die mir alle 
Werte aus diesem Bereich in pseudozufälliger Reihenfolge ausspuckt, 
jeden genanu einmal. Die Qualität des Zufallsgenerators muß nicht sehr 
hoch sein.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren