Null-Pointer in main()...



  • Hallo!

    Ich lese aus einer Textdatei die Zeilenanzahl und Spaltenanzahl eines Gleichungssystems heraus (nrow, ncol). Darüber hinaus noch die Koeffizienten-Matrix. Ich habe im Sinne einer modularen Programmierung eine header-Datei für die Deklaration der zwei Variablen und des Pointers auf A (Matrix) geschrieben plus eine .c Datei für die Definition der Funktion. Diese Funktion kann ich in Application.c starten und mir die Werte im Konsolenfenster ausgeben lassen. Allerdings kann ich außerhalb der Funktion nur auf die Werte nrow u ncol zugreifen. A ist Nullpointer... Ich dachte, durch #include RealAlloc.h ist der Pointer in Application.h bekannt und zeigt auf die Werte (die ich mir auch an der Konsole ausgeben lassen konnte)...

    Über Hilfe würde ich mich freuen!

    Header Datei ReadAlloc.h:
    -------------------------

    #pragma once
    #include "stdafx.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    extern int nrow, ncol;
    extern double** A;
    
    void read(int *rows_nrow, int *columns_ncol, double** Matrix);
    

    Datei ReadAlloc.c:
    ------------------

    #define extern
    #include "ReadAlloc.h"
    #undef extern
    
    void read(int *rows_nrow, int *columns_ncol, double** Matrix)
    {
    	int i, j;
    	double temp;
    	FILE *fp;
    	fp = fopen("inputMatrix1.txt", "r");
    
    	if (fp == NULL)
    
    	{
    		puts("Fehler beim Oeffnen\n");
    
    		exit(EXIT_FAILURE);
    	}
    
    	else
    
    		puts("erfolgreich geoeffnet!\n");
    
    	while (fgetc(fp) != ':')
    	{
    	}
    
    	fseek(fp, +1, SEEK_CUR);
    
    	fscanf(fp, "%d", &*rows_nrow);
    	printf("%d\n", *rows_nrow);
    
    	while (fgetc(fp) != ':')
    	{
    	}
    
    	fseek(fp, +1, SEEK_CUR);
    
    	fscanf(fp, "%d", &*columns_ncol);
    	printf("%d\n", *columns_ncol);
    
    	//////////////////////Speicher für Matrix A//////////////////////////////
    	Matrix = (double **)malloc((*rows_nrow + 1) * sizeof(double *));        //
    																		    //
    	for (i = 0; i <= *rows_nrow; i++)									    //
    	{																	    //
    		Matrix[i] = (double *)malloc((*columns_ncol + 1) * sizeof(double)); //
    	}                                                                       //
    	/////////////////////////////////////////////////////////////////////////
    
    	while (fgetc(fp) != ':')
    	{
    	}
    
    	fseek(fp, +1, SEEK_CUR);
    
    	for (i=0; i <= *rows_nrow - 1; i++)
    	{
    		for (j = 0; j <= *columns_ncol - 1; j++)
    		{
    
    			fscanf(fp, "%lf", &temp);
    
    			if (feof(fp) && (i *j) < ((*rows_nrow) * (*columns_ncol)))
    			{
    				printf("ERROR zu wenig Elemente\n");
    				getchar();
    			}
    
    			Matrix[i][j] = temp;
    			printf("%d%d %f\n", i, j, Matrix[i][j]);
    
    		}
    
    	}
    
    	fclose(fp);
    	getchar();
    
    	//return EXIT_SUCCESS;
    
    }
    

    Datei Application.c:
    --------------------

    // Application.c : Definiert den Einstiegspunkt für die Konsolenanwendung.
    //
    
    #include "stdafx.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    #define extern
    #include "ReadAlloc.h"
    #undef extern
    
    int main()
    {
    
    	read(&nrow, &ncol, A);
    
    	printf("%d%d\n", nrow, ncol);
    	//printf("%f\n", A[0][0]);
    	getchar();
    
    	return 0;
    }
    

    Mod-Edit: Code-Tags



  • Fehler ist bestimmt in der Read-Funktion.
    Mach Single-Step (im Debugger) und schau dir alles genau an.


  • Mod

    Gobale Variablen mit einbuchstabigen Bezeichnern 😮 . Makroumdefinition von Schlüsselwörtern 😮 😮 . Nein, das tu ich mir nicht an, das Problem ist selbstverschuldet.

    Maßnahmen zu Selbsthilfe:

    • Keine globalen Variablen!
    • Vernünftige Bezeichner.
    • Keine Makros.
    • Ganz bestimmt keine Makros für reservierte Bezeichner!
    • Ein Array ist kein Zeiger, ein Zeiger ist kein Array.
    • Ein 2D-Array ist noch viel weniger ein Zeiger auf Zeiger, und ein Zeiger auf Zeiger ist noch viel weniger ein 2D-Array.
    • Klare Trennung von Zuständigkeiten: Wieso verwaltet hier eine Lesefunktion sowohl Dateien als auch Speicherplatz?

    Wenn das umgesetzt wurde, sind wie so langsam an dem Punkt, dass man helfen kann, falls noch Probleme bestehen.



  • Wo definierst du den dein globales A ?

    Das extern double** A; ist eine Deklaration.

    A ist ein sehr, sehr unglücklicher Name für eine globale Variable. Nötig ist sie (global) auch nicht.

    read ist eine Funktion aus dem POSIX-Standard. Diese Namen sollte man (auch wenn man sie nicht nutzt) nicht verwenden.

    Zum Problem:

    Beim Aufruf von read wird der Inhalt von A nach Matrix kopiert. (Der Inhalt ist eine Adresse)
    Matrix ist eine lokale Variable innerhalb von read, deren Existenz mit dem Ende/Verlassen von read aufhört.

    Da verhält sich ein Zeiger nicht anders, als eine "normale" Variable.

    Wenn du den Wert von Matrix wieder in A haben möchtest, so musst du die Adresse von A an read übergeben.
    Dann hast du einen "Dreifach-Zeiger" (Viel Spaß).
    Oder du gibst Matrix als Rückgabewert der Funktion zurück. Dann musst du diesen beim Aufruf aber auswerten.


  • Mod

    DirkB schrieb:

    Wo definierst du den dein globales A ?

    Das extern double** A; ist eine Deklaration.

    Er definiert vor dem Inklude per Makro "extern" zu "". Damit wird aus der Deklaration eine Definition. Und ich glaube, ich höre an der Stelle lieber auf mit der Analyse, sonst fang ich an vor Schmerz zu schreien.



  • SeppJ schrieb:

    Er definiert vor dem Inklude per Makro "extern" zu "". Damit wird aus der Deklaration eine Definition. Und ich glaube, ich höre an der Stelle lieber auf mit der Analyse, sonst fang ich an vor Schmerz zu schreien.

    Aua.

    ~(ich hatte mir den Code noch unformatiert angesehen und erst später geantwortet)~



  • #include "stdafx.h"
    

    Schrott. Unnötige Abhängigkeiten.

    #define extern
    #undef extern
    

    Schrott. Standardheader sind tabu, und Schlüsselworte natürlich auch. Immer und überall.

    extern double** A;
    

    In Zusammenhang mit Mehrfachdimensionen immer Schrott weil UB.



  • Hi!

    Ich hab meine Dateien noch mal überarbeitet... ich kann mir die eingelesenen werte in dem main modul ausgeben lassen. manchmal... teilweise erhalte ich aber den im titel genannten fehler der dann die drei in der main funktion genutzten funktionen betrifft. manchmal geht es, dann wieder nicht. Ich arbeite mit visual studio, version 15.1. Durch googeln habe ich den eindruck gewonnen, es könnte mit der verknüpfung der verschiedenen dateien zu tun haben?!

    Ich schicke hier noch mal den aktuellen code. Über Hilfe würde ich mich freuen!

    Application.c:
    --------------

    #include "stdafx.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    #include "ReadAlloc.h"
    
    int main()
    {
    
    	int nrow, ncol;
    	double **matrixFromText;
    
     //read nrow and ncol, then alloc matrix, then read matrix
    //////////////////////////////////////////////////////////
    	readNrowNcol(&nrow, &ncol);
    
    	matrixFromText = allocMatrix(nrow, ncol);
    
    	fillMatrix(matrixFromText, nrow, ncol);
    
    	//Test, ob einlesen funktioniert...
    	  printf("%d %d\n", nrow, ncol);
    	//printf("\n%f\n", matrixFromText[0][0]);
    	  printf("\n%f\n", matrixFromText[2][0]);
    	  getchar();
    ////////////////////////////////////////////////////////////
    
    	return 0;
    }
    

    ReadAlloc.c:
    ------------

    #include "ReadAlloc.h"
    
    extern int nrow, ncol;
    extern double **matrixFromText;
    
    void readNrowNcol(int *nrow, int *ncol)
    {
    	double temp;
    	FILE *fp;
    	fp = fopen("inputMatrix1.txt", "r");
    
    	if (fp == NULL)
    
    	{
    		puts("Fehler beim Oeffnen\n");
    		getchar();
    		exit(EXIT_FAILURE);
    	}
    
    	else
    
    		puts("erfolgreich geoeffnet!\n");
    
    	while (fgetc(fp) != ':')
    	{
    	}
    
    	fseek(fp, +1, SEEK_CUR);
    
    	fscanf(fp, "%d", nrow);
    	/*printf("%d\n", nrow);
    	getchar();*/
    
    	while (fgetc(fp) != ':')
    	{
    	}
    
    	fseek(fp, +1, SEEK_CUR);
    
    	fscanf(fp, "%d", ncol);
    
    }
    
    double **allocMatrix(int nrow, int ncol)
    {
    	int i;
    	double** Matrix;
    	Matrix = (double**)malloc((nrow) * sizeof(double *));
    	for (i = 0; i <= nrow; i++)
    	{
    		Matrix[i] = (double *)malloc((ncol) * sizeof(double));
    	}
    
    	return Matrix;
    
    }
    
    void fillMatrix(double **Matrix, int nrow, int ncol)
    {
    	int i, j;
    	double temp;
    	FILE *fp;
    	fp = fopen("inputMatrix1.txt", "r");
    
    	if (fp == NULL)
    
    	{
    		puts("Fehler beim Oeffnen\n");
    
    		exit(EXIT_FAILURE);
    	}
    
    	else
    
    		puts("erfolgreich geoeffnet!\n");
    
    	while (fgetc(fp) != '#')
    	{
    	}
    
    	fseek(fp, +1, SEEK_CUR);
    
    	for (i = 0; i <= nrow - 1; i++)
    	{
    		for (j = 0; j <= ncol - 1; j++)
    		{
    
    			fscanf(fp, "%lf", &temp);
    
    			if (feof(fp) && (i * j) < ((nrow - 1) * (ncol - 1)))
    			{
    				printf("ERROR zu wenig Elemente\n");
    				getchar();
    			}
    
    			Matrix[i][j] = temp;
    
    		}
    	}
    
    	fclose(fp);
    }
    

    ReadAlloc.h:
    ------------

    #pragma once
    #include "stdafx.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    void readNrowNcol(int *nrow, int *ncol);[code]
    
    double **allocMatrix(int nrow, int ncol);
    
    void fillMatrix(double **Matrix, int nrow, int ncol);
    


  • Du musst alle benötigten .c Dateien in dein Project mit aufnehmen.

    Der C-Compiler macht das nicht für dich.



  • DirkB-mobil schrieb:

    Du musst alle benötigten .c Dateien in dein Project mit aufnehmen.

    Der C-Compiler macht das nicht für dich.

    danke für die Antwort! Wie denn? ich habe im ordner "Quelldateien" mithilfe des kontextmenüs c dateien hinzugefügt. Ich dachte (hatte gehofft), somit werden diese bestandteil des projekts und beim kompillieren nicht ignoriert...

    ich bin leider mit der microsoft hilfe nicht glücklich geworden, sonst würde ich nicht noch mal fragen...



  • Über das Project-Menu von Visual-Studio geht das.



  • stekuntze schrieb:

    Hi!

    ReadAlloc.c:
    ------------

    extern int nrow, ncol;
    extern double **matrixFromText;
    

    Was willst du mit diesen beiden extern -Zeilen bezwecken? Lösche beide Zeilen komplett! Du übergibst doch die Variablen als Parameter an die Funktionen.

    Zur Matrix: es ist häufig sinnvoller/einfacher, nur ein 1d-Feld der Länge rows*cols zu erzeugen und den entsprechenden Index von Hand zu berechnen (also z.B. row*cols+col oder col*rows+row - je nachdem, welches Layout du im RAM haben willst) anstatt hier eine 1d-Matrix mit double* zu erzeugen und dann jedem dieser pointer wieder eine 1d-Matrix zu erzeugen.



  • wob schrieb:

    stekuntze schrieb:

    Hi!

    ReadAlloc.c:
    ------------

    extern int nrow, ncol;
    extern double **matrixFromText;
    

    Was willst du mit diesen beiden extern -Zeilen bezwecken? Lösche beide Zeilen komplett! Du übergibst doch die Variablen als Parameter an die Funktionen.

    Zur Matrix: es ist häufig sinnvoller/einfacher, nur ein 1d-Feld der Länge rows*cols zu erzeugen und den entsprechenden Index von Hand zu berechnen (also z.B. row*cols+col oder col*rows+row - je nachdem, welches Layout du im RAM haben willst) anstatt hier eine 1d-Matrix mit double* zu erzeugen und dann jedem dieser pointer wieder eine 1d-Matrix zu erzeugen.

    War gestern mein erster Versuch, mal mit mehreren Dateien zu arbeiten. Ich hab jetzt nur noch lokal Variablen in der main() funktion im main modul. ich glaube, das soll auch ein guter style sein, auf globale variablen zu verzichten. ich habe mein programm zum laufen gebracht, nachdem ich meine header in so ne präprozessorabfrage gepackt hab, ob die schon mal kompilliert wurden oder so (hatte das in nem buch gesehen) a la:

    #ifndef XYZ
    #define XYZ
    
    void readNrowNcol(int *nrow, int *ncol);
    double **allocMatrix(int nrow, int ncol);
    void fillMatrix(double **Matrix, int nrow, int ncol);
    
    #endif //
    

    ich bin glücklich, dass es geht. wenn mir noch jemand etwas zu den hintergründen sagen kann, wäre schön 🙂

    der typ mit der matrix ist auch gut. vielleicht ändere ich das noch.



  • stekuntze schrieb:

    ich glaube, das soll auch ein guter style sein, auf globale variablen zu verzichten.

    wenn du mal zeit und lust hast, programmier mal ein größeres projekt (k.a. 2000 zeilen dürften reichen) und nimm nur globale variablen. danach (wenn du überhaupt so weit kommst) weißt du sozusagen aus 1. quelle, warum globale variablen so "böse" sind. 😃 aber manchmal gehts nicht anders.

    ich bin glücklich, dass es geht. wenn mir noch jemand etwas zu den hintergründen sagen kann, wäre schön 🙂

    manchmal musst du headerdateien an mehreren stellen einbringen und wenn dus geschickt programmierst, hast du dann ne endlosschleife.



  • Jede C-Datei wird vom Compiler als eine unabhängige Einheit übersetzt.
    Bei den #include -Zeilen wird die angegebene Datei eingefügt.
    Der Compiler macht daraus eine sog. Object-Datei (meist *.o oder *.obj)

    Wenn alle C-Dateien übersetzt sind, kommt der Linker und bindet diese Object-Dateien mit den Bibliotheken zu einer ausführbaren Datei (oft *.exe) zusammen.

    In den Objectdateien stehen auch noch die Namen der enthaltenen und benötigten Funktionen und (globalen) Variablen.

    Wenn da etwas fehlt, gibt es eine Fehlermeldung wie "error LNK2019: Verweis auf nicht aufgelöstes externes Symbol"
    Das LNK deutet auf den Linker, danach sollte auch noch das genaue Symbol (Name) des fehlenden Teils genannt werden.

    stekuntze schrieb:

    ich habe mein programm zum laufen gebracht, nachdem ich meine header in so ne präprozessorabfrage gepackt hab, ob die schon mal kompilliert wurden oder so (hatte das in nem buch gesehen) a la:

    Das sind sog. Include-Guards.

    Die sind dann wichtig, wenn du eine Header-Date (*.h) in einer anderen Header-Datei einbindest.
    In deinem Beispiel hast du stdio.h zweimal eingefügt.
    Einmal direkt mit #include <stdio.h>, dass zweite mal über #include "ReadAlloc.h"
    Das wird damit verhindert.


Anmelden zum Antworten