Question

As in the headline. Simple exercise, trying to learn structures and other essential c functionality. Here is a structure containing a char[] and a number, I try to save its values in a file and read them back. I read through a lot of topics concerning Seg.fault by fopen(), but can't find my mistake! Someone here who knows why fopen() does crash in this instance? Any suggestions and criticism on the matter is welcome!

The function where the Segfault happens is load():

void load(struct Telephon *structure, int *counter)
{
    char filename[255];
    char puffer[255], puffercpy[255];
    int i, c, newline_count;
    size_t strlaen;
    FILE *datei=NULL;
    char *token=NULL;

    printf("\033[0;35mWelche Datei oeffnen?\033[0m\n");
    scanf("%s", filename);
    //emptystdin();
    //strlaen=strlen(filename);
    //printf("%d", strlaen);
    //filename[strlaen+1] = '\0';

    //printf("\n%s", filename);

    datei = fopen(filename, "r");

    if(datei==NULL)
    {
        printf("\033[0;31mKonnte Datei %s nicht oeffnen.\033[0m\n", filename);
    }
    else
    {
        while ( (c=fgetc(datei)) != EOF ) //count lines of file
        {
            if ( c == '\n' )
            {
                newline_count++;
            }

        }

        for(i=0; i<=newline_count; i++) //get values in between ";" 
        {
            fgets(puffer, 254, datei);
            strcpy(puffercpy, puffer);

            token = strtok(puffercpy, ";");
            *counter = atoi(token);

            token = strtok(NULL, ";");
            strcpy(structure[i].name, token);

            token = strtok(NULL, ";");
            structure[i].nummer = atoi(token);

        }

    fclose(datei);
    }
    return;

}   

The whole code, main is at the end:

telephonListen.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#define MAX 100

struct Telephon
{
    char         name[210];
    unsigned int nummer;
}TELE[MAX];

char* gotTime(char *timestrg)
{
    time_t now;
    now = time(NULL);
    strftime (timestrg, 19, "%d.%m.%Y, %H:%M", localtime (&now));
    return timestrg;
}

void printT(struct Telephon *structarray, int addcount)
{   int i;
    if(addcount==0)
    {
        printf("\033[0;31mEs sind noch keine Eintraege vorhanden!\033[0m\n");
        return;
    }
    else
    {
        for(i=0; i<addcount; i++)
        {
            printf("\nEintrag Nr.%d\n%s:\t%d\n",i+1, structarray[i].name, structarray[i].nummer);
        }
        return;
    }

}

void eingabe(int num, struct Telephon *structarray)
{
    size_t inputlen;
    int check;
    if(num>MAX)
    {
        printf("\033[0;31mMaximale Anzahl von Eintraegen erreicht!\033[0m\n");
        return;
    }
    else
    {
        printf("\n\033[0;35mNamen eingeben:\t\033[0m");
        //fgets(structarray[num].name, MAX, stdin);
        fgets(structarray[num].name, 209, stdin);
        inputlen=strlen(structarray[num].name);
        structarray[num].name[inputlen-1]='\0';
        printf("\n\033[0;35mNummer eingeben:\t \033[0m");
        do
        {
            check = scanf("%10u", &structarray[num].nummer);
        }while( getchar()!='\n');
        fflush(stdin);

        if(check==1)
        {
            printf("Ihr Kontakt wurde angelegt!\n%s:\t%u\n", structarray[num].name ,structarray[num].nummer);
        }
        else
        {
            printf("Fehler bei der Eingabe. Kontakt wurde nicht angelegt!");
            return;
        }

        return;
    }

}
void writeFile(struct Telephon *structure, char *zeitf, int counter)
{
    char filename[255];
    int i;
    FILE *datei;

    if(counter>0)
    {
        printf("\033[0;35mIn welche Datei soll das Telephonbuch geschrieben werden?\n(Achtung: Vorhandene Dateien werden ueberschrieben!)\t\033[0m\n");
        scanf("%s", filename);
        getchar();
        datei = fopen(filename, "w");
        if(NULL == datei)
        {
            printf("\033[0;31mKonnte Datei %s nicht öffnen.\033[0m\n", filename);
        }

        fprintf(datei, "Telephonverzeichnis vom %s\nNAME\t\t|NUMMER\n\n", zeitf);
        for(i=0; i<counter; i++)
        {
            fprintf(datei, "%s\t\t|%d\n", structure[i].name, structure[i].nummer);
        }
        printf("\033[0;32mDatei gespeichert.\033[0m\n");
        fclose(datei);
    }
    else
    {
        printf("\033[0;31mEs sind noch keine Eintraege vorhanden!\033[0m\n");
        return;
    }
    return;

}

void change(struct Telephon *structure, int count)
{
    int eintragnum;
    if (count == 0)
    {
        printf("\033[0;31mEs sind noch keine Eintraege vorhanden!\033[0m\n");
        return;
    }
    else
    {
        printT(structure, count);
        printf("\033[0;31mWelcher Eintrag soll geaendert werden?\033[0m\n");
        do
        {
            scanf("%d", &eintragnum);
        }while(getchar()!='\n');

        if(eintragnum<1||eintragnum>count)
        {
            printf("\033[0;31mBitte die Nummer [zwischen %d und %d]\n des zu aendernden Eintrags eingeben!\033[0m\n", 1, count);
        }
        else
        {
            eingabe(eintragnum-1, structure);
        }

    }

    return;
}
void emptystdin()
{
  int c;
  while( ((c = getchar()) != EOF) && (c != '\n') );
}
void searchContact(struct Telephon *structure, int count)
{
    char searchC;
    int inputlen;
    int i=0;
    int countcompare;
    if (count == 0)
    {
        printf("\033[0;31mEs sind noch keine Eintraege vorhanden!\033[0m\n");
        return;
    }
    else
    {
        printf("Anfangsbuchstabe:\t");
        scanf("%c", &searchC);
        emptystdin();

        for(i=0; i<count; i++)
            {
                if(structure[i].name[0]==searchC)
                {
                    printf("Eintrag gefunden:\n");
                    printf("Nr. %d\nName:\t%s\nNummer:\t%u\n", i+1, structure[i].name, structure[i].nummer);
                }

            }
        return;
    }

}


void save(struct Telephon *structure, int counter)
{
    char filename[255];
    int i;
    FILE *datei;

    if(counter>0)
    {
        printf("\033[0;35mUnter welchem Dateinamen speichern?\n(Achtung: Vorhandene Dateien werden ueberschrieben!)\t\033[0m\n");
        scanf("%s", filename);
        emptystdin();
        datei = fopen(filename, "w");
        if(NULL == datei)
        {
            printf("\033[0;31mKonnte Datei %s nicht anlegen.\033[0m\n", filename);
        }

        for(i=0; i<counter; i++)
        {
            fprintf(datei, "%d;%s;%d\n", i+1, structure[i].name, structure[i].nummer);
        }
        printf("\033[0;32mDatei gespeichert.\033[0m\n");
        fclose(datei);
    }
    else
    {
        printf("\033[0;31mEs sind noch keine Eintraege vorhanden!\033[0m\n");
    }
    return;
}




void load(struct Telephon *structure, int *counter)
{
    char filename[255];
    char puffer[255], puffercpy[255];
    int i, c, newline_count;
    size_t strlaen;
    FILE *datei=NULL;
    char *token=NULL;

    printf("\033[0;35mWelche Datei oeffnen?\033[0m\n");
    scanf("%s", filename);
    //emptystdin();
    //strlaen=strlen(filename);
    //printf("%d", strlaen);
    //filename[strlaen+1] = '\0';

    //printf("\n%s", filename);

    datei = fopen(filename, "r");

    if(datei==NULL)
    {
        printf("\033[0;31mKonnte Datei %s nicht oeffnen.\033[0m\n", filename);
    }
    else
    {
        while ( (c=fgetc(datei)) != EOF ) //Zeilen in Datei zählen
        {
            if ( c == '\n' )
            {
                newline_count++;
            }

        }

        for(i=0; i<=newline_count; i++) //CVS parsen/auslesen
        {
            fgets(puffer, 254, datei);
            strcpy(puffercpy, puffer);

            token = strtok(puffercpy, ";");
            *counter = atoi(token);

            token = strtok(NULL, ";");
            strcpy(structure[i].name, token);

            token = strtok(NULL, ";");
            structure[i].nummer = atoi(token);

        }

    fclose(datei);
    }
    return;

}

int main(void)
{
    int auswahl;
    int count = 0;
    char zeit[20];
    char buffer[2];
    struct Telephon *structptr; //malloc(MAX*(sizeof(TELE)));
    structptr = TELE;

    gotTime(zeit);
    system("clear");
    printf("Telephonkontaktverwaltung\t%s\n", zeit);


    do
    {

        printf("\033[30;47m1: Kontakt hinzufuegen\t2: Kontakte anzeigen\n3: Kontakt aendern\t4: Als Datei speichern\n5. Kontakt suchen\n6. Als CVS sichern\t7. Aus CVS laden\n8. Beenden\nEine der Ziffern eingeben, mit Enter bestaetigen\033[0m\n");

        /*
        scanf("%d", &auswahl);
        scanf("%c", &buffer);

        fgets(buffer, 2, stdin);
        if(isdigit(buffer[1]))
        {
            auswahl=atoi(buffer);
        }
        else
        {
            printf("Eine der Nummern eingeben um Aktion auszufuehren!\n");
        }


        do
        {
           scanf("%d", &auswahl);
        }while(getchar()!='\n');

        fgets(buffer, 2, stdin);
        sscanf(buffer, "%d", &auswahl);
        */

        scanf("%d", &auswahl);
        emptystdin();




        switch (auswahl)
        {
            case 1  :   eingabe(count++, structptr);
                        break;
            case 2  :   printT(structptr, count);
                        break;
            case 3  :   change(structptr, count);
                        break;
            case 4  :   writeFile(structptr, gotTime(zeit), count);
                        break;
            case 5  :   searchContact(structptr, count);
                        break;
            case 6  :   save(structptr, count);
                        break;
            case 7  :   load(structptr, &count);
                        break;
            case 8  :   printf("ENDE\n");
                        break;
            default :   printf("Eine der Nummern eingeben um Aktion auszufuehren!\n");
                        break;
        }



    }while(auswahl!=8);

    return EXIT_SUCCESS;
}
Was it helpful?

Solution

Use rewind().

Between the while() and for() loops, the file need to start at the beginning again.

while ( (c=fgetc(datei)) != EOF ) //count lines of file
  { ...}
rewind(datei);
for(i=0; i<=newline_count; i++) //get values in between ";"
   { ...}

Strongly suggest avoid using scanf() and fgets(,,stdin). Recommend one. Preferable fgets().

You likely want scanf(" %c", instead of scanf("%c",. (Add space).


Minor Idea:
Not that English is the be-all end-all language, but OP may want to consider something like

// Bold Red "Could not create file" EOL
const char *Err_FileCreation_format = "\033[0;31mKonnte Datei %s nicht anlegen.\033[0m\n"
printf(Err_FileCreation_format, filename);
// or 
#define Err_FileCreation_fmt1 "\033[0;31mKonnte Datei "
#define Err_FileCreation_fmt2 " nicht anlegen.\033[0m\n"
printf(Err_FileCreation_fmt1 "%s" Err_FileCreation_fmt2, filename);

OTHER TIPS

Assuming undefined behaviour hadn't been invoked prior to a call to fopen() the only way to make it crash is to pass it a non-initialised or non-0-terminated character array as file name or mode.

So to avoid this properly initialise all variables used to hold a file name and/or mode by declaring it like:

char filename[256] = "";

To avoid allowing scanf() to read in more then filenamecan hold do like this:

scanf("%255s", filename);

Update:

This code

        while ( (c=fgetc(datei)) != EOF ) //count lines of file
        {
            if ( c == '\n' )
            {
                newline_count++;
            }

        }

reads until the end of the file.

So this code

        for(i=0; i<=newline_count; i++) //get values in between ";" 
        {
            fgets(puffer, 254, datei);
            strcpy(puffercpy, puffer);

            token = strtok(puffercpy, ";");
            *counter = atoi(token);

            token = strtok(NULL, ";");
            strcpy(structure[i].name, token);

            token = strtok(NULL, ";");
            structure[i].nummer = atoi(token);

        }

would not be able to read anything, as eof had already been reached.

However the code does not test whether fgets() might have failed but happily starts parsing what it didn't read and ... crashes during atoi()ing a token pointing to NULL.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top