簡體   English   中英

C 中的已退出分段錯誤結構

[英]Exited segmentation fault Struct in C

所以我有一個結構,我想制作一個 function 並從用戶輸入中獲取循環並將它們存儲到結構中。 但是在 1 個循環之后,程序因分段錯誤而崩潰,我找不到問題所在。

這是錯誤:

在此處輸入圖像描述

> clang-7 -pthread -lm -o main main.c
> ./main
4
ath
67
68
thes
exited, segmentation fault
>

這是代碼:

#define STR 100000
typedef struct city{
 float x;
 float y;
 char *name;
}City;

City *GetCities(int *N){
int i;
City *p;
char c;
scanf("%d",&*N);
p=malloc(sizeof(City));
p->name=malloc(STR*sizeof(char));

if (p->name==NULL){
  printf("Could not find enough memory");
}

for (i=0; i<*N; i++){
   while((c = getchar()) !='\n' && c!= EOF);
   fgets(p[i].name,STR,stdin);
   p[strcspn(p[i].name,"\n")].name="\0";
   p[i].name=realloc(p[i].name,(strlen(p[i].name)+1)*sizeof(char));
   scanf("%f ",&p[i].x);
   scanf("%f",&p[i].y);
} 
return p;
}

這將起作用:

//includes were missing
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define STR 100000
typedef struct city{
 float x;
 float y;
 char *name;
}City;

City *GetCities(int *N){
  int i;
  char c;
  City *list, *city;
  //N is already a pointer so using a '&*' is confusing and I'm unsure whether this is at all valid syntax
  scanf("%d", N);
  //allocate enough memory! multiplied by number of cities
  list = malloc(sizeof(City) * (*N));
  
  for (i=0; i < *N; i++) {
     //use pointer arithmetic to get the current city from the allocated block
     //this needs to be done only once, now you can go on and reuse it extensively
     city = list + i;
     
     city->name = malloc(STR * sizeof(char));
     if (city->name==NULL){
       printf("Could not find enough memory");
     }
     while((c = getchar()) !='\n' && c!= EOF);
     //i hope rest is clear
     fgets(city->name, STR, stdin);
//use city->name[strlen(city->name)-1]='\0' instead?
     city->name[strcspn(city->name,"\n")]='\0';
     //at least you didn't forget the +1 in the realloc! :-)
     city->name = realloc(city->name,(strlen(city->name)+1)*sizeof(char));
     scanf("%f ", &city->x);
     scanf("%f",  &city->y);
  }
  
  return list;
}

//please also show the main, but I guess it was something like this
int main () {
    int i, n;
    City *cities, *city;
    cities = GetCities(&n);
    for (i=0; i < n; i++) {
        city = cities + i;
        printf("The %dth city \"%s\" got coordinates x=%f and y=%f!\n", i, city->name, city->x, city->y);
        //don't forget to free the name
        free(city->name);
    }
    //don't forget to free the memory
    free(cities);
}

我還建議使用較小的行長緩沖區並循環運行 fgets 以節省內存空間。

要求輸入包括即將到來的數據的總數通常是一個糟糕的設計選擇,並且很容易刪除該要求。 例如:

    #include <stddef.h>                                                                
    #include <stdio.h>                                                                 
    #include <stdlib.h>                                                                
                                                                                       
    FILE * xfopen(const char *, const char *);                                         
    void * xrealloc(void *, size_t, size_t, void *);                                   
                                                                                       
    struct city{                                                                       
            float x, y;                                                                
            char *name;                                                                
    };                                                                                 
                                                                                       
    int                                                                                
    get_city(struct city *e)                                                           
    {                                                                                  
            int c;                                                                     
            char *end;                                                                 
            size_t cap = 32;                                                           
            e->name = xrealloc(NULL, 1, cap, &end); 
            /* Copy one line.  We coould use getline(), or "%m[^\n]" */
            while( (c = getchar()) != EOF && c != '\n' ){                              
                    *end++ = c;                                                        
                    if( end == e->name + cap ){                                        
                            e->name = xrealloc(e->name, 1, cap += 32, &end);           
                    }                                                                  
            }                                                                          
            *end = '\0';                                                               
            if( c == EOF ){                                                            
                    return EOF;                                                        
            }                                                                          
            if( (c = scanf("%f %f ", &e->x, &e->y)) != 2 ){                            
                    if( c != EOF ){                                                    
                            fprintf(stderr, "Invalid input\n");                        
                    }                                                                  
                    return EOF;                                                        
            }                                                                          
            return 0;                                                                  
    }                                                                                  
                                                                                       
    struct city *                                                                      
    GetCities(int *n)                                                                  
    {                                                                                  
            size_t cap = 4;                                                            
            struct city *e, *p = xrealloc(NULL, sizeof *p, cap, &e);                   
            while( get_city(e) != EOF ){                                               
                    if( ++e == p + cap ){                                              
                            p = xrealloc(p, sizeof *p, cap += 4, &e);                  
                    }                                                                  
            }                                                                          
            *n = e - p;                                                                
            return p;                                                                  
    }

    int                                                                                
    main(void)                                                                         
    {                                                                                  
            int n;                                                                     
            while( (n = getchar()) != EOF && n != '\n' ){                              
                    ;  /* Discard first line of input */                               
            }                                                                          
            struct city *p = GetCities(&n);                                            
            struct city *e = p + n;                                                    
                                                                                       
            for( ; p < e; p++ ){                                                       
                    printf("%s: %f, %f\n", p->name, p->x, p->y);                       
            }                                                                          
            return 0;                                                                  
    }                                                                                  
                                                                                       
    void *                                                                             
    xrealloc(void *buf, size_t num, size_t siz, void *endvp)                           
    {                                                                                  
            char **endp = endvp;                                                       
            char *b = buf;                                                             
            ptrdiff_t offset = b && endp && *endp ? *endp - b : 0;                     
            b = realloc(b, num * siz);                                                 
            if( b == NULL ){                                                           
                    perror("realloc");                                                 
                    exit(EXIT_FAILURE);                                                
            }                                                                          
            if( endp != NULL ){                                                        
                    *endp = b + offset;                                                
            }                                                                          
            return b;                                                                  
    }  

要使您的程序正常運行,您需要做三件基本的事情:

  1. 分配N個城市
  2. 對於每個城市,在讀取名稱之前為名稱分配 memory
  3. 正確終止名稱(分配 null 字符,而不是字符串)

這是更正后的代碼:

City *GetCities(int *N)
{
    int i;
    City *p;
    char c;

    scanf("%d", N);
    p = malloc(*N * sizeof(City));
    for (i = 0; i < *N; i++) {
        p[i].name = malloc(STR * sizeof(char));
        if (p[i].name == NULL) {
            printf("Could not find enough memory");
        }
        while ((c = getchar()) != '\n' && c != EOF);
        fgets(p[i].name, STR, stdin);
        p[i].name[strcspn(p[i].name, "\n")] = '\0';
        scanf("%f ", &p[i].x);
        scanf("%f", &p[i].y);
    }
    return p;
}

剩下的就是驗證輸入並確保對 malloc 的第一次調用沒有失敗。 您可能還需要一個 function 來釋放分配的 memory。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM