Problem mit Doppelpointer (für fortgeschrittene)



  • hallo,

    hab hier ein "kleines" Problem.

    will aus einer *.txt datei, in der folgendes steht zeilenweise auslesen:

    a/b + c/d
    a/b - c/d
    a/b * c/d
    a/b / c/d

    Es funktioniert auch. Es wird in einem String gespeichert und wird wieder der main() übergeben.

    Diesen String übergebe ich wieder der Funktion getrow() und sie soll es in **Inhalt speichern. Also in der Form: Inhalt[Zeilennummer][Zeichen].

    Bei meiner Ausführung sind die funktionen in *.h ausgelagert, hab es aber zur Einfachkeit unter der main() geschrieben. Näheres siehe kommentare im Programm.

    Problem: Fehler bei der Ausgabe. Wahrscheinlich folgefehler durch die Funktion.

    Programmiere in C und nicht in C++. => simulieren von call-by-reference

    /*******************************************************************************
      Name: Aufgaben Mathematik
      Author: T.N.
      Date: 06.12.07
      Version: 1.6
    
    *******************************************************************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include "Dokument_Auslesen.h"
    #include "ReadDocLength.h"
    #include "GetRow.h"
    #include <dos.h>
    
    void ReadDocLength(int *AnzahlZeilen,int *AnzahlZeichen, char Str[]);  //Funktion zum Auslesen der Anzahl der benötigten Zeilen und Spalten
    void getrow(char Str[], char **Inhalt, int AnzahlZeilen, int AnzahlZeichen);  //Funktion zum  Zeilenweise auslesen
    
    int main()
    {	
    	char *String;	// Pointer, in dem das *.txt gespeichert wird
    	char **Inhalt;  //Inhalt[i][j] i = Zeilen j = Spalten/Zeichen
    	int i = 0;	//Zähl- Variable
    	int j = 0;	//Zähl- Variable
    	int ZeichenNr = 0;	//Zähl- Variable für String (=> String[ZeichenNr])
    	int Zeilen = 0;		// Wird in einer ausgelagerten Funktion mit "4" beschrieben
    	int ZeichenProZeile = 0;	//wird in einer ausgelagerten Funktion mit "9" beschrieben
    
     /* Aufrufen der Funktion "Dokument Auslesen" mit Übergabe des Dokumentpfades */
    
    	String = getstr("C:\\Documents and Settings\\T\\Desktop\\Nikos\\C Programmierung\\Unfertige Aufgaben\\Aufgaben\\Aufgaben.txt");
    	printf("\n%s\n", String);
    
    	/* Funktion zum Einlesen der Anzahl der Zeilen und Zeichen pro Zeile */
    
    	ReadDocLength(&Zeilen, &ZeichenProZeile, String);
    
    	printf("\n\n zeilen: %i\n ZeichenProZeile:%i\n",Zeilen,ZeichenProZeile);
    
    		/*!!!!! Funktion zum separaten Speichern der Zeilen !!!!!!!!!!!!*/
    
    	getrow(String, Inhalt, Zeilen, ZeichenProZeile);  // Diese Funktion hat evtl. Fehler
    
    // Ab hier stürzt das Programm ab
    
    				/* Ausgabe der einzelnen Zeichen/ Strings */
    
    for(i=0; i < Zeilen; i++)
    {					
    	for(j = 0; j < ZeichenProZeile; j++)
    		{
    		printf("%c", Inhalt[i][j]);
    		}
    	printf("\n");
    }
    	printf("\n");
    
      system("PAUSE");	
      return 0;
    }
    
    //nachstehende funktion ist bei mir in einer Header- Datei untergebracht
    
    void getrow(char Str[], char **Inhalt, int AnzahlZeilen, int AnzahlZeichen)
    {	
    	int	ZeichenNr = 0;
    	int i=0, j=0;
    
    /************* Speicher reservieren für die int-Zeiger (=zeile) ***************/
    
       Inhalt = (char **)malloc(AnzahlZeilen * sizeof(char *));
    
    /******************** Speicher reservieren für die Spalten ********************/
    	for(i = 0; i < AnzahlZeilen; i++) 
        	{
    		Inhalt[i] = (char *)malloc(AnzahlZeichen * sizeof(char));
    	}
    
    /****** Auslesen der Zeilen und Speichern in unterschiedlichen Variablen ******/
    
    	for( i = 0, ZeichenNr = 0; Str[ZeichenNr] != '\0' ; i++, ZeichenNr++)  //so lange Wiederholen, bis ein '\0' eingelesen wird, d.h. das Dateiende erreicht ist.
    									       //EOF wurde in einer anderen Funktion mit '\0' ersetzt im String.
    	{
    		for(j = 0; (Str[ZeichenNr] != '\n') && (Str[ZeichenNr] != '\0'); ZeichenNr++, j++)
    		{
    			Inhalt[i][j] = Str[ZeichenNr];
    		}
    
    		if(Str[ZeichenNr] == '\0')  // ZeichenNr um 1 reduzieren, wenn ein '\0' ermittelt wird, weil am Ende ZeichenNr um 1 erhöht wird
    		{
    			ZeichenNr = ZeichenNr - 1;
    		}
    		printf("%i", **Inhalt);
    	}
    }
    


  • Wieso arbeitest du nicht einfach mit den filestreams (if- / ofstream ) von fstream.h und benutzt getline( )?

    Oder wurde euch dieser Weg vorgeschrieben?

    Gruß Tobi.



  • Programmiere in C und nicht in C++



  • ok



  • genau, das ist das Problem 😉
    C!

    das habe ich im C- Kurs in der Ausbildung angefangen, weil mir langweilig war, und da sollten wir C üben... ist also zwar keine Pflicht, aber so lernt man besser den Umgang mit Pointern.

    Nur bin ich jetzt an den Punkt wo ich nicht mehr weiterkomme.

    Ich kann auch den ganzen Quell- Code hochladen, wenn es hier im Forum geht,damit ihr es ausprobieren könnt. Müsst mir nur sagen, wie man es macht...



  • Um den Fehler zu finden, könntest du assert benutzen.
    In assert.h ist assert defienirt.
    Im unteren code, wo ich den fehler vermutte hab ich assert reingemacht.
    Falls zur Laufzeit ein assert auftritt wird über den reservierten bereich geschrieben.

    /****** Auslesen der Zeilen und Speichern in unterschiedlichen Variablen ******/
    
        for( i = 0, ZeichenNr = 0; Str[ZeichenNr] != '\0' ; i++, ZeichenNr++)  //so lange Wiederholen, bis ein '\0' eingelesen wird, d.h. das Dateiende erreicht ist.
                                               //EOF wurde in einer anderen Funktion mit '\0' ersetzt im String.
        {
            for(j = 0; (Str[ZeichenNr] != '\n') && (Str[ZeichenNr] != '\0'); ZeichenNr++, j++)
            {
                assert( i < AnzahlZeilen );
                assert( j < AnzahlZeichen );
                Inhalt[i][j] = Str[ZeichenNr];
            }
    
            if(Str[ZeichenNr] == '\0')  // ZeichenNr um 1 reduzieren, wenn ein '\0' ermittelt wird, weil am Ende ZeichenNr um 1 erhöht wird
            {
                ZeichenNr = ZeichenNr - 1;
            }
            printf("%i", **Inhalt);
        }
    }
    


  • hmmm...

    assert bringt keine fehlermeldung zurück. ich schau auch in andere stellen nach... falls ich was finde melde ich mich nochmal...



  • frage: ist "assert(Str[ZeichenNr] != '\0');" zulässig?
    weil das programm stürzt bei mir dann ab.
    er erwartet assert(int), ne?



  • assert ist ein Makro, d. h. ist nicht Typsicher. Ich habe eher den Verdacht, dass dein Index nicht gültig ist. Bekommst du eine access violation?

    greetz, Swordfish



  • es wird nichts mit access violation ausgegeben, aber das Programm stürzt einfach ab, und das lässt mich vermuten, dass es eine access violation sein muss.

    das hässliche ist, dass ich devc++ verwende und dass das debugging nicht geht. kennt ihr eine andere IDE, die freeware und besser ist? (mit guter debugging funktion?)



  • Visual Studio 2008 Express Edition.



  • Du uebergibst eine Kopie der Adresse auf die *"char *Inhalt" zeigt an Deine funktion "getrow".
    Alles was Du dann in "getrow" damit anstellst, hat keinen Einfluss auf das tatsaechliche "Inhalt".

    Vorschlag:

    char** getrow(char Str[], int AnzahlZeilen, int AnzahlZeichen)
    {
      char **Inhalt;
      ...
      return Inhalt;
    }
    

    oder:

    getrow(String, &Inhalt, Zeilen, ZeichenProZeile);
    ...
    void getrow(char Str[], char ***Inhalt, int AnzahlZeilen, int AnzahlZeichen) 
    {
      *Inhalt = (char **)malloc(AnzahlZeilen * sizeof(char *)); 
      ...
    }
    

    darueber hinaus solltest du sicherstellen, dass hier:

    Inhalt[i][j] = Str[ZeichenNr];
    

    0<=i<AnzahlZeilen und 0<=j<AnzahlZeichen gilt.



  • Hab deinen 2. Codevorschlag veruscht.

    demnach müsste das allokieren der 2. Dimension so lauten:

    for(i = 0; i < AnzahlZeilen; i++) 
        {
    		**(Inhalt + i) = (char *)malloc(AnzahlZeichen * sizeof(char));
    	}
    

    da stürzt aber das programm ab, nachdem i den wert 3 erreicht... hab ich da nen fehler gemacht?

    für den 2. Vorschlag hab ich die schleife so ergänzt, zur sicherheit:
    for( i = 0, ZeichenNr = 0; Str[ZeichenNr] != '\0' || i < AnzahlZeilen; i++, ZeichenNr++)

    Übrigens: Danke für die tolle Hilfe, die hier geleistet wird! 👍



  • hab mal das ganze Programm hochgeladen ins web, damit es auch mal ausprobiert werden kann...
    so findet man evtl. leichter den fehler...

    http://www.loaditup.de/179493.html



  • hat keiner einen neuen Verbesserungsvorschlag 😕



  • In deiner getstr-Funktion holst du zu wenig speicher für Str:

    Str = malloc( sizeof(laenge) );
    

    Das sizeof ist hier falsch. In laenge steht, wie lang die Datei ist. sizeof( laenge ) ergibt aber nur die Größe einer size_t-Variablen.

    In getrow greifst du falsch auf Inhalt zu:

    **(Inhalt + i)
    

    Damit inkrementierst du Inhalt selbst, den Zeiger auf dein char**. Dort steht aber nichts. Du musst das inkrementieren, auf das Inhalt zeigt:

    *((*Inhalt) + i) = malloc(AnzahlZeichen * sizeof(char));
    

    Und hier stolperst du über die Operatorreihenfolge:

    *Inhalt[i][j] = Str[ZeichenNr];
    

    [] bindet stärker als *. Du musst also klammern:

    (*Inhalt)[i][j] = Str[ZeichenNr];
    


  • ok, es geht.

    im 1. allokieren, hattest du einen kleinen fehler noch drin gehabt (1 * zu viel) (auf mein verschulden vlt.)

    das mit getstr stimmt, aber komischerweise funktionierts auch, wenns falsch ist..

    danke!



  • und noch ne frage zum Verständniss:

    In "Inhalt" steht die Adresse der Variablen.

    Also kann ich **(Inahlt + i) schreiben, da ich ja lediglich die Adresse um i erhöhe.

    genauso wie *((*Inhalt)+i) den Inhalt von *Inhalt um i erhöht (also auch die Adresse um i) und dann dereferenziert wird.



  • Jetzt wollte ich die Zeilenlänge variabel machen, und dafür die einzelnen Zeilenlängen in einem dynamischen Array speichern, welches einer Funktion per Call-by-Reference übergeben wird, doch da kommt folgende Fehlermeldung in der Funktion: "assignment makes pointer from integer without a cast"

    void ReadDocLength(int *AnzahlZeilen, int **AnzahlZeichen, char Str[])
    {			
    		int ZeichenNr = 0;
    		char Zaehler;
    		int i = 0;
    
    		/* Anzahl der Zeichen lesen und in "AnzahlZeichen" speichern */
    
    	for(ZeichenNr = 0, i = 0, *(AnzahlZeichen+0) = 0, Zaehler = 1; Str[ZeichenNr] != '\0'; ZeichenNr++)
    	{
    	    *(AnzahlZeichen+i) = Zaehler ;  // DIESE ZEILE HAT DEN FEHLER
    		Zaehler++;
    
    printf("\nAnzahlZeichen[i]: %i", *(AnzahlZeichen+i));
    
    		if(Str[ZeichenNr] == '\n')
    		{
    			i++;
    			Zaehler = 0;
    		}	
    	}	
    
    system("pause");
    

Anmelden zum Antworten