Zahlen in dynamisches Int-Array aus Textdatei auslesen



  • Hallo Leute,

    bin recht noch am Anfang meines Lernfortschritts und befasse mich gerade mit dynamischen Arrays.

    Ich habe eine Textdatei in der folgendes steht:

    Werte im Intervall: 1 2 3 4 5 6 7 8 9 10 
    Exponent: 5
    Anzahl: 10
    
    Potenzen: 1 32 243 1024 3125 7776 16807 32768 59049 100000
    

    Nun sollen die Potenzen in einem dynamischen int-Array gespeichert werden, wobei die Größe des Arrays mit der in der Textdatei angegebenen Anzahl bestimmt werden soll.

    Hier der derzeitige Stand:

    (typedefs in der Headerdatei)

    typedef int *pointer_auf_int;	
    typedef pointer_auf_int *dyn_int_array_t;
    

    (die eigentliche cpp)

    #include "main.h"
    
    void auslesen() {
    
    	char filename[255];
    	char *new_filename;
    
    	printf("Welche Datei soll geöffnet werden? ");
    	scanf("%s", &filename);
    
    	dyn_int_array_t numbers = new pointer_auf_int[5];
    
    	int exp;
    
    	readPowersFromTextFile(filename, numbers, exp);
    
    	delete[] numbers;
    }
    
    errno_t readPowersFromTextFile(const char* filename, dyn_int_array_t& numbers, int& exp){
    
    	FILE *datei;
    	int sizeofarray;
    	const char trennzeichen = ' ';
    	char search_anzahl[8] = "Anzahl:";
    	char search_potenzen[10] = "Potenzen:";
    	char buffer[255], *token;
    
    	datei = fopen(filename, "r");
    
    	if (datei != NULL) {
    
    		printf("Die Datei \"%s\" wird geoeffnet...\n", filename);
    
    		//Größe des zu befüllenden Arrays ermitteln
    		while (fgets(buffer, 255, datei) != NULL ){
    			if(strstr(buffer, search_anzahl) != 0) {
    				token = strtok(buffer, &trennzeichen);
    				if(token != NULL) {
    					token = strtok(NULL, &trennzeichen);
    					sizeofarray = atoi(token);
    					//numbers = (dyn_int_array_t)realloc((void*)numbers, sizeofarray * sizeof(int));
    
    				}else {
    					printf("Fehler: dyn_int_array konnte nicht vorbereitet werden!");
    				}
    			}
    
    			//Array befüllen
    			while (fgets(buffer, 255, datei) != NULL ){
    				if(strstr(buffer, search_potenzen) != 0) {
    
    					token = strtok(buffer, &trennzeichen);
    					if(token != NULL) {
    						//Hier soll eine for-Schleife hin, die das Array mithilfe der unteren Zeile befüllt
    						token = strtok(NULL, &trennzeichen);
    					}		
    				}			
    			}
    		}
    
    	}else {
    
    		printf("Die Datei \"%s\" existiert nicht!\n", filename);
    		return EXIT_FAILURE;
    	}
    
    	fclose(datei);
    
    	return EXIT_SUCCESS;
    
    }
    

    Ich gebe ja das numbers Array als Referenz der Funktion readPowersFromTextFile mit.

    Wie greife ich im Allgemeinen auf den Wert solcher übergebenen Arrays zu bzw verändere diesen? (zB. numbers[0] = 34)

    Wie in Zeile 45 zu sehen ist, versuche ich das Array zu reallozieren. Ist dies richtig? Gibts einen anderen Weg?

    Ich weiß nicht, ob es ein Denkfehler ist oder ich einen Aspekt bei den Pointern übersehen hab.

    Bitte um Hilfe.



  • new/delete sind C++.
    Hier ist C und kein C++. Deine Frage ist also falsch adressiert.



  • Das ist auch bereits das einzige, alles andere ist ja C.



  • mrpool89 schrieb:

    Das ist auch bereits das einzige, alles andere ist ja C.

    nicht ganz, das

    (..., dyn_int_array_t& numbers, int& exp)
    

    ist auch nicht c.

    dein beispiel dürfte gar nicht kompilieren, weil bezeichner doppelt sind ...

    warum willst du das array reallozieren, wenn die anzahl der elemente bekannt ist?
    du übergibst einen int** du hast einmal zu wenig dereferenziert.

    btw. arbeitet man beim reallozieren gern mit einem zweiten zeiger, weil realloc
    fehlschlagen könnte und dadurch der zuvor allozierte speicherplatz nicht mehr zugänglich wäre, was ein speicherleck zur folge hätte.

    int* tmp = realloc((*numbers, sizeofarray * sizeof(int));
    if (tmp) *numbers = tmp;
    else /*fehlerbehandlung...*/
    


  • Hm wusste nicht, dass call-by-reference nicht zu C gehört, aber naja^^

    warum willst du das array reallozieren, wenn die anzahl der elemente bekannt ist?

    Ich dachte mir halt, dass man das Array erst einmal anlegen muss, die 5 ist eine vorläufig gewählte Größe.

    Mit

    int* tmp
    

    bzw.

    *numbers = tmp;
    

    hätte ich doch immernoch einen Pointer. Wie manipuliere ich aber die Werte des Arrays selbst?



  • Hat niemand einen Rat? 😞


  • Mod

    mrpool89 schrieb:

    Hat niemand einen Rat? 😞

    Das ist absoluter Anfängerkram, der spätestens im dritten oder vierten Kapitel eines guten Buches (d.h. kein Buch aus dem Galileo-Verlag) erklärt werden sollte. Da dir diese Grundlagen fehlen, wäre es eine sehr gute Idee, sich solche ein Buch zu besorgen. Denn wenn es schon an der Benutzung von Funktionen und Zeigern hapert, dann wird dynamische Speicherverwaltung sowieso nix. Wenn man C nicht von C++ unterscheiden kann, dann erst recht nicht. Man kann nicht den fortgeschrittenen Kram machen, ohne die Grundlagen sicher zu beherrschen.

    Klingt hart, ist aber so.



  • Mir ist durchaus bewusst, dass das Anfängerkram ist und ja ich habe ein C Buch vom Galileo Verlag. Dort ist auch call-by-reference erklärt(weshalb ich auch annahm, dass es zu C gehört), in weiteren Tutorials sowie in diesem Buch ist auch der Umgang mit Pointern und auch Pointer als Rückgabewert erklärt.

    Ich dachte man könnte mir hier einen Denkanstoß geben, was ich falsch mache. Anstatt mir zu erzählen, wieso ich die Finger von der dynamischen Speicherverwaltung lassen sollte, hätteste genauso gut in 2 Sätzen mir den Weg zur Lösung weisen können.



  • du gehst an das ganze ein wenig umständlich heran. versuch es doch für den anfang
    ohne die umständlichen typdefinitionen mit einem einfachen int* array.



  • Da gibt es noch mehr Baustellen bei dir:

    char filename[255];
    ...
        scanf("%s", &filename);
    //              ^ da
    

    oder

    const char trennzeichen = ' ';
    ...
                    token = strtok(buffer, &trennzeichen);
    

    strtok() erwarten zwei Zeiger auf '\0'-terminierte Zeichenketten.
    Für &trennzeichen trifft dies nicht zu.

    Und Call-by-Reference ist in C die Bezeichnung der Parameterübergabe über die Adresse der Variable.
    Das musst aber alles du als Programmierer machen. Da hilft dir der Compiler nicht.
    Du musst dafür sorgen das die Adresse der Variable als Parameter übergeben wird.

    Und wenn du ein Buch hast, gibt es auch ein Beispiel wie man Arrays in Funktionen behandelt.
    Meist bei den Stringfunktionen.



  • Ok. Wenn ich beispielsweise so ein Array anlege:

    int* numbers = new int[10];
    

    dann die funktion aufrufe

    readPowersFromTextFile(filename, *numbers, exp);
    

    in der so das Array befülle

    for (int i = 0;i < 10; i++) {						
    numbers[i] = strtok(NULL, &trennzeichen);
    }
    

    sagt er mir:

    Error: Der Ausdruck muss den Typ "pointer-to-object" aufweisen
    

    Das ist ja der eigentliche Kern meiner frage gewesen.
    Mal abgesehen vom der Speicherreservierung aufm Heap, sollte doch das wenigstens funktionieren.



  • Ein Sternchen zuviel...

    #include <iostream>
    
    void foo( int *p ) {
    
    	for( size_t i = 0; i < 10; i++ ) {
    
    		p[i] = i + 1;
    	}
    }
    
    int main( )
    {
    	int *numbers = new int[10];	
    
    	foo( numbers );
    
    	for( size_t i = 0; i < 10; ++i ) {
    		std::cout << "numbers[ " << i << " ] = " << numbers[ i ] << '\n';
    	}
    
    	delete [] numbers;
    }
    

    mrpool89 schrieb:

    strtok(NULL, &trennzeichen);
    

    Was soll dabei 'rauskommen?

    ot @others: Wie lang' sind denn noch Ferien!? 😮


  • Mod

    mrpool89 schrieb:

    Ok. Wenn ich beispielsweise so ein Array anlege:

    int* numbers = new int[10];
    

    Dann ist das C++ und wir brauchen an der Stelle gar nicht erst weiter reden, denn in C++ würde man den Rest ganz anders machen.

    dann die funktion aufrufe

    readPowersFromTextFile(filename, *numbers, exp);
    

    Dann ist *numbers ind der Notation von oben vom Typ int, was nicht zur Funktionssignatur passt. Das teilt dir der Compiler mit.

    in der so das Array befülle

    for (int i = 0;i < 10; i++) {						
    numbers[i] = strtok(NULL, &trennzeichen);
    }
    

    Das ist, mit Verlaub, totaler Blödsinn. Guck mal, was strtok zurück gibt und wie man es aufruft.

    Mal abgesehen vom der Speicherreservierung aufm Heap, sollte doch das wenigstens funktionieren.

    Nein, auch der ganze Rest ist ziemlich falsch. Dir fehlen einfach die Grundlagen, egal wie sehr dir das nicht gefällt. Wenn einfache Funktionsaufrufe schon falsch sind, dann kann der Rest auch nichts werden. Du bekommst einfach viel zu viele Nebenfehler, wenn du die einfachen Sachen nicht beherrscht. In den fünf Zeilen waren vier dicke Fehler, von denen drei mit deinem eigentlichen Problem nichts zu tun hatten. Und dabei war eine dieser Zeilen nur ein '}'!

    und ja ich habe ein C Buch vom Galileo Verlag.

    Hier ist das Problem. Die sind schlecht, deren Bücher.

    Ich dachte man könnte mir hier einen Denkanstoß geben, was ich falsch mache. Anstatt mir zu erzählen, wieso ich die Finger von der dynamischen Speicherverwaltung lassen sollte, hätteste genauso gut in 2 Sätzen mir den Weg zur Lösung weisen können.

    Das geht eben nicht, weil du die Grundlagen nicht kannst. Sonst würde ich dir schon zu helfen versuchen, aber dir zu sagen, dass du erst noch was anderes lernen musst, ist momentan die beste Hilfe, die du bekommen kannst.



  • for (int i = 0;i < 10; i++) {                        
    numbers[i] = strtok(NULL, &trennzeichen);
    }
    

    Damit will erreichen, dass jedes token in jeweils ein Element von numbers geschrieben wird.

    strtok zerlegt einen String in Token.
    string1 ist der zu zerlegende String, string2 enthält die Trennzeichen, anhand derer der String zerlegt wird.

    Der erste Aufruf von strtok überspringt führende Trennzeichen, liefert einen Zeiger auf den Anfang des ersten gefundenen Token in string1 zurück

    Folgende Aufrufe von strtok mit dem Wert NULL anstelle des Arguments string1 liefern Zeiger auf weitere Token.

    Auf diese Weise bekommen ich auch die Anzahl für die Größe des Arrays ausgelesen
    Textdatei:

    Anzahl: 10
    

    Cpp:

    while (fgets(buffer, 255, datei) != NULL ){
    			if(strstr(buffer, search_anzahl) != 0) {
    				token = strtok(buffer, &trennzeichen);
    				if(token != NULL) {
    					token = strtok(NULL, &trennzeichen);
    					sizeofarray = atoi(token);
    				}
    			}
    		}
            ...
    

    Ja ich werde mich wohl weiter selber irgendwie durchkämpfen müssen.
    Ich danke trotzdem für die Antworten.


  • Mod

    mrpool89 schrieb:

    Ja ich werde mich wohl weiter selber irgendwie durchkämpfen müssen.

    Dann kann ich dir auch nicht weiter helfen. Wenn du die Grundlagen einfach nicht lernen möchtest, sondern stattdessen "kämpfen" willst, dann wirst du scheitern, das verspreche ich dir. Egal wie viel "Kampfeswille" du dir einredest. Aber ich kann dich nicht vor dir selber schützen, sag bloß nicht, dass man dich nicht gewarnt hätte. Die Grundlagen hättest du in einer Woche gelernt, nun wirst du eine Woche Fluchen und am Ende doch nichts haben und auch nichts gelernt haben. Tja.



  • mrpool89 schrieb:

    [...] ich werde mich wohl weiter selber irgendwie durchkämpfen müssen.

    Dort vielleicht? 🤡



  • mrpool89 schrieb:

    eine Menge über strtok

    nur ...
    .. ein Zeiger auf int ist aber etwas anderes als ein Zeiger auf char.
    Dein Array numbers und der Rückgabewert von strtok passen nicht zusammen.

    Und ein 'Zeiger auf char' oder 'Array von char' muss kein String (im Sinne von C) sein.


Anmelden zum Antworten