fopen приводит к segfault

Как в заголовке. Простое упражнение, пытающееся изучить структуры и другие важные функции c. Вот структура, содержащая char[] и число, я пытаюсь сохранить его значения в файле и прочитать их обратно. Я прочитал много тем, касающихся Seg.fault от fopen(), но не могу найти свою ошибку! Кто-нибудь здесь, кто знает, почему fopen() не работает в этом случае? Приветствуются любые предложения и критика по этому поводу!

Функция, в которой происходит Segfault, — 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;

}   

Весь код, main находится в конце:

phoneListen.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;
}

person rrrrn    schedule 14.10.2013    source источник
comment
Лучше спросить на Code Review.   -  person haccks    schedule 14.10.2013
comment
Мне сказали, что спрашивайте только о рабочем коде там, а о неисправном коде здесь.   -  person rrrrn    schedule 14.10.2013
comment
Тот, что в load(. . .)   -  person rrrrn    schedule 14.10.2013
comment
То есть вы запускаете программу, вводите 7, вводите имя файла и программа вылетает на fopen()?   -  person alk    schedule 14.10.2013
comment
Да, точно. fopen() работает в других функциях   -  person rrrrn    schedule 14.10.2013
comment
Из чего вы сделали вывод, что fopen() вылетает? Очень может быть, что код после fopen() не работает.   -  person alk    schedule 14.10.2013
comment
Пожалуйста, смотрите мой обновленный ответ.   -  person alk    schedule 14.10.2013


Ответы (2)


Используйте 1_.

Между циклами while() и for() файл нужно снова начать с начала.

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

Настоятельно рекомендуем избегать использования scanf() и fgets(,,stdin). Рекомендовать один. Желательно fgets().

Скорее всего, вы хотите scanf(" %c", вместо scanf("%c",. (Добавить пробел).


Второстепенная идея:
Не то, чтобы английский был универсальным языком, но OP, возможно, захочет рассмотреть что-то вроде

// 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);
person chux - Reinstate Monica    schedule 14.10.2013
comment
Это был звонок на rewind() теперь все работает, спасибо большое за рекомендации! И второстепенная Идея особенно! Раньше глаза болели. - person rrrrn; 15.10.2013
comment
Добро пожаловать в СО. Подумайте о том, чтобы проголосовать за ответы, которые оказались полезными. - person chux - Reinstate Monica; 15.10.2013
comment
На самом деле текст ошибки на неанглийском языке незначителен (и нет причин его разделять), но я рекомендовал бы не встраивать escape-последовательности напрямую. Либо используя curses/ ncurses для систем POSIX, либо, по крайней мере, используя #define ANSI_Bold_Red "\033[0;31m" и #define ANSI_Off "\033[0m" и используя строку компилятора конкатенация, например printf(ANSI_Bold_Red "Konnte Datei %s nicht anlegen." ANSI_Off "\n", filename); Обратите внимание, что нет запятых лучше, чем строки. - person mctylr; 16.10.2013

Предполагая, что поведение undefined не было вызвано до вызова fopen(), единственный способ вызвать его сбой — передать ему неинициализированный или не 0-терминированный массив символов в качестве имени файла или режима.

Поэтому, чтобы избежать этого, правильно инициализируйте все переменные, используемые для хранения имени файла и/или режима, объявив его следующим образом:

char filename[256] = "";

Чтобы не позволить scanf() читать больше, чем filenameможет удерживать, сделайте следующее:

scanf("%255s", filename);

Обновление:

Этот код

        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);

        }

не сможет ничего прочитать, так как eof уже достигнут.

Однако код не проверяет, мог ли fgets() потерпеть неудачу, но радостно начинает синтаксический анализ того, что он не прочитал, и... аварийно завершает работу во время atoi()ing токена, указывающего на NULL.

person alk    schedule 14.10.2013
comment
Я попытался инициализировать указатель файла с помощью NULL; segfault происходит, даже когда я напрямую передаю имя существующего имени файла. Неверное имя файла устанавливает указатель файла на NULL, программа работает нормально. Но правильное имя файла приводит к segfault. Пробовал вышеупомянутую инициализацию с помощью . - person rrrrn; 14.10.2013
comment
@rrrrn: Ты сделал #include <stdio.h>, не так ли? - person alk; 14.10.2013
comment
да, stdio.h включен. Я получаю следующий вывод после сообщения об ошибке сегментации: процесс вернул 139 (0x8B) - person rrrrn; 14.10.2013