2013-10-14 102 views
1

正如标题。 简单的练习,试图学习结构和其他必要的c功能。 这是一个包含char []和一个数字的结构,我尝试将它的值保存在一个文件中并将其读回来。 我通过fopen()了解了很多关于Seg.fault的主题,但是找不到我的错误! 有人知道为什么fopen()在这种情况下会崩溃吗? 欢迎任何关于此事的建议和批评!的fopen导致段错误

其中段错误发生的功能是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; 

} 

整个代码,主要是在末端:

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; 
} 
+0

多问上的代码审查。 – haccks

+0

有人告诉我应该只询问工作代码,并在这里询问有问题的代码 – rrrrn

+0

'load(...)'中的一个' – rrrrn

回答

1

使用rewind()

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",。 (添加空间)。


小点子:
这并不是说英文是BE-所有最终所有的语言,但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); 
+0

这是'rewind()'调用现在一切正常,非常感谢您的建议!特别是小的想法!这是以前眼中的痛苦。 – rrrrn

+0

欢迎来到SO。考虑投票答案,证明有用。 – chux

+1

实际上,非英文的错误文本很小(并且没有理由将其分开),但是我会推荐不直接嵌入转义序列。无论是使用curses/[ncurses](http://invisible-island.net/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);'注意**没有**逗号更好的字符串。 – mctylr

0

假设未定义的行为有不之前调用fopen()被调用,使其崩溃的唯一途径就是通过它非初始化或非0 - 叔以文件名或模式将rminated字符数组。

因此,为了避免这种正确,宣布它像初始化用于保存文件名和/或模式的所有变量:

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()期间崩溃,指向NULL的令牌。

+0

我试着用NULL初始化文件指针;即使我直接传递现有文件名的名称,segfault也会发生。错误的文件名将filepointer设置为NULL,程序工作正常。但正确的文件名会导致段错误。 “”也尝试了上述初始化。 – rrrrn

+0

@rrrrn:你没有'#包括',不是吗? – alk

+0

是的,包括stdio.h。分段错误后,我得到以下输出:msg:process returned 139(0x8B) – rrrrn