mikrocontroller.net

Forum: PC-Programmierung Problem bei Pointer-/Parameterübergabe und malloc


Autor: Mark Huber (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

habe zwei kleine Funktionen geschrieben, die aus dem main aufgerufen 
werden:

int main(void)
{
    int *m, *n;
    double *arrayzeiger;
    einlesen (m, n, arrayzeiger);
    ausgeben (m, n, arrayzeiger);
    return (0);
}

void einlesen (int *m, int *n, double *arrayzeiger)
{
    int temp;
    char Dateiname[50];

    FILE *Datei;
    printf ("bitte Dateinamen eingeben\n");
    scanf ("%s", Dateiname);
    Datei = fopen (Dateiname, "r");
    if (Datei == NULL)
    {
    printf ("Datei nicht gefunden\n");
    exit (1);
    }
    fscanf (Datei, "%i", m);
    fscanf (Datei, "%i\n", n);
    ZV_c = (double*) malloc (n  sizeof (double*));
    for (temp= 0; temp< *n; temp++)
  {
    fscanf (Datei, "%lf\n", &arrayzeiger[temp]);
  }
    fclose (Datei);
}

void ausgeben (int *m, int *n, double *arrayzeiger)
{
  int temp;
  for (temp= 0; temp< *n; temp++)
  {
    printf ("nachher: = %lf\n", arrayzeiger[temp]);
  }
}

Die einlesen Funktion holt sich aus der Datei die Größe des Arrays und 
belegt anschließend mittels malloc Speicher fürs das Array.
Das Problem ist nur, dass mir die Funktion nicht den neuen Zeiger von 
malloc zurückgibt, der also nur lokal existiert :=(
Deshalb habe ich den Aufruf der Funktion auch schon mal zu 
&(*arrayzeiger) verändert, womit ich ja eigentlich die Adresse des 
Zeigers in die Funktion bekommen sollte. Aber das klappt auch nicht.
Wie macht man das richtig?

Gruß,

Mark

P.S. Wenn ich den Speicher mit malloc schon vorher im main reserviere 
geht alles gut (da der Zeiger ja auch nicht verändert wird).

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist sowieso Zufall, dass das Programm funktioniert. Du speicherst in 
der Zeile "fscanf (Datei, "%lf\n", &arrayzeiger[temp]);" wegen der 
uninitialisierten Variable arrayzeiger irgendwo im Speicher.

Einlesen könnte den allozierten Speicher als Pointer an Main 
zurückgeben. Und am Ende von main() (oder bei neuem Aufruf von 
einlesen()) kannst du den per free() auch wieder freigeben.
void * einlesen (int *m, int *n, double *arrayzeiger) // <==
{
    int temp;
    char Dateiname[50];
    FILE *Datei;

    printf ("bitte Dateinamen eingeben\n");
    scanf ("%s", Dateiname);
    Datei = fopen (Dateiname, "r");

    if (Datei == NULL)
    {
       printf ("Datei nicht gefunden\n");
       exit (1);
    }

    fscanf (Datei, "%i", m);
    fscanf (Datei, "%i\n", n);

    if (arrayzeiger != NULL) // <==
    {
       free(arrayzeiger);
    }

    arrayzeiger = (double *) malloc (*n * sizeof (double*)); // <==

    if (arrayzeiger == NULL) // <==
    {
       printf ("Speicherproblem\n");
       fclose (Datei);
       exit (1);
    }

    for (temp = 0; temp < *n; temp++)
    {
       fscanf (Datei, "%lf\n", &arrayzeiger[temp] /* oder arrayzeiger+temp */); // <==
    }

    fclose (Datei);

    return ((void *)arrayzeiger); // <==
}

int main(void)
{
    int *m, *n;
    double *arrayzeiger = NULL; // <==

    arrayzeiger = (double *) einlesen (m, n, arrayzeiger);
    ausgeben (m, n, arrayzeiger);
    free((void *)arrayzeiger); // <==

    return (0);
}

  

Autor: Arc Net (arc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eigentlich dürfte noch weniger funktionieren...
da die Zeiger alle uninitialisiert sind d.h. wenn einlesen in main 
aufgerufen wird, bekommt einlesen irgendetwas nur keine Zeiger auf 
benutzbare Variablen in denen die neuen Werte gespeichert werden 
könnten.
Soll arrayzeiger nach dem Aufruf auf den angeforderten Speicher zeigen, 
muss einlesen entweder den neuen Zeiger zurückliefern (double* 
einlesen(int* m, int* n) oder man übergibt einen Zeiger auf einen 
Zeiger.
// aus
    int *m, *n;
    double *arrayzeiger;
    einlesen(m, n, arrayzeiger)

// müsste entweder
    int m, n;
    double *arrayzeiger;
    einlesen(&m, &n, &arrayzeiger);
// oder 
    int mv, nv;
    int *m = &mv, *n = &nv;
    einlesen(m, n, &arrayzeiger)
// werden

  

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt. Typ. Fall von Problemfixierung bei mir.

Autor: Mark Huber (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vielen Dank für die schnelle Rückmeldung. Nun bleibt noch ein Problem: 
später sollte die Funktion mehrere Arrays einlesen, d.h. ich müstte auch 
mehrere Zeiger zurückgeben. Aber wenn ich erst mal weiß wie ich die 
Zeiger korrekt in die Funktion ein/übergeben bekomme, dann probliere ich 
da erst mal weiter und melde mich evtl. noch mal.

Danke,

Mark

Autor: Mark Huber (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

habe das ganze nun zu
void einlesen (int *m, int *n, double **arrayzeiger)
{
    int temp;
    char Dateiname[50];

    FILE *Datei;
    printf ("bitte Dateinamen eingeben\n");
    scanf ("%s", Dateiname);
    Datei = fopen (Dateiname, "r");
    if (Datei == NULL)
    {
    printf ("Datei nicht gefunden\n");
    exit (1);
    }
    fscanf (Datei, "%i", m);
    fscanf (Datei, "%i\n", n);
    if (*arrayzeiger != NULL)
    {
    free (*arrayzeiger);   // <== evtl. ist hier auch ein Fehler
    }
    *arrayzeiger = (double*) malloc (*n * sizeof (double*));
    if (*arrayzeiger == NULL)
    {
       printf ("Speicherproblem\n");
       fclose (Datei);
       exit (1);
    }
    for (temp = 0; temp < *n; temp++)
  {
    fscanf (Datei, "%lf\n", &(*arrayzeiger)[temp]);
  }
    fclose (Datei);
}

void ausgeben (int m, int n, double **arrayzeiger)
  int temp;
  for (temp= 0; temp< *n; temp++)
  {
    printf ("nachher: = %lf\n", arrayzeiger[temp]);
  }

int main(void)
{
    int m, n;
    double *arrayzeiger = NULL;
    einlesen (&m, &n, &arrayzeiger);
    ausgeben (m, n, &arrayzeiger);
    //free (*ZV_c);   // <== schlägt immer fehl
    return (0);
}

geändert. Nun läuft es (mal wieder), aber die free Aufrufe scheitern 
(bzw. der letzte auf jeden Fall, bei dem in der einlesen Funktion bin 
ich mir unsicher). Insofern nehme ich stark an, dass da mmer noch was 
nicht stimmt. Warum der letzte free Aufruf scheitert wundert mich, das 
das main ja jetzt den in arrayzeiger die Position/Adresse des 
eigentlichen Arrays hat.
Werde da wohl noch mal ne Nacht drüber schlafen müssen... Muss gestehen, 
so richtig klar ist mir das leider noch nicht.

Mark

Autor: Arc Net (arc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das free in einlesen ist soweit richtig, dafür das free in main nicht.
Die Funktion ausgeben dürfte auch nur falsche Werte ausgeben, ausser 
arrayzeiger[temp] wäre ein Tippfehler und sollte *arrayzeiger[temp] 
sein.
arrayzeiger[temp] wäre nur dann richtig, wenn auch nur ein einfacher 
Zeiger übergeben werden würde. So wie es jetzt da steht würde der tempte 
(nicht vorhandene Zeiger auf einen double Zeiger) ausgewertet.

Zur Verdeutlichung:
 
    double* array1 = (double *)malloc(sizeof(double) * 4);
    double* array2 = (double *)malloc(sizeof(double) * 4);
    double array3[4] = { 1.0, 2.0, 3.0, 4.0 };

    double* ptr = array1;
    double* ptr2[3] = { array1, array2, array3 };

    double** dptr1 = &ptr;
    double** dptr2 = &ptr2[0];

    array1[0] = 1.1; array1[1] = 2.1; array1[2] = 3.1; array1[3] = 4.1; 
    array2[0] = 1.2; array2[1] = 2.2; array2[2] = 3.2; array1[3] = 4.2; 

    // was geben die folgenden printfs aus?
    printf("%p", dptr[0]);
    printf("%f", *dptr[0]);
    printf("%f", **dptr);
    printf("%p", dptr2[1]);
    printf("%f", *dptr2[1]);
    printf("%f", **dptr2);

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> double* array1 = (double *)malloc(sizeof(double) * 4);

Den Rückgabewert von malloc sollte man nicht casten. Der Cast ist 
unnötig und verdeckt potentielle Fehler.

Autor: Arc Net (arc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Magnus wrote:
>> double* array1 = (double *)malloc(sizeof(double) * 4);
>
> Den Rückgabewert von malloc sollte man nicht casten. Der Cast ist
> unnötig und verdeckt potentielle Fehler.

In C++ ist dieser Cast zwingend nötig. In C nicht...

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In C++ verwendet man eh gleich den Operator new. In C sollte man wie 
gesagt den Cast besser weglassen.

Autor: Mark Huber (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

habe nun alles soweit ohne Fehler am laufen, nur das letzte free 
bereitet mir nach wie vor noch Kopfzerbrechen. Meiner Meinung (und dem 
C-Buch Beispiel) nach sollte ein

    [...]
    ausgeben (m, n, &arrayzeiger;
    if (ZV_c != NULL)
    {
    free (arrayzeiger);
    }
    return (0);
}

richtig sein. Das fliegt mir aber immer noch um die Ohren. Da ich 
gelesen habe, dass nach Terminierung des Programms der Speicher eh 
wieder freigegebn wird, hat das jetzt Zeit bis morgen. Werde da noch mal 
ein paar Dinge ausprobieren. Ist zwar mit Sicherheit kein sauberer 
Programmierstil, aber das zählt ja zum Glück auch nicht...
Bis hierhin: vielen Dank für eure Hilfe, habe wieder was dazugelernt und 
steige da (so langsam) durch.

Mark

Autor: Peter Mulski (Firma: Sorry-No) (edison24)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
muss das nicht "free(*arryzeiger)" heißen....aslo mit "*"?

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nö.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.