【问题标题】:Exited segmentation fault Struct in CC中退出分段错误结构
【发布时间】:2021-04-27 16:54:22
【问题描述】:

所以我有一个结构,我想用一个循环从用户输入中获取函数并将它们存储到结构中。但是在 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;
}

【问题讨论】:

  • 使用调试器。至少它会立即准确地告诉您哪一行代码触发了段错误。获取最少的信息并将其发布在问题中。也可以使用调试器检查崩溃点的状态以及导致它的状态。
  • p[i].name, p 不是数组
  • 为什么要做这件事:scanf("%d",&amp;*N);
  • @IrAM scanf 是 Cities 用户想要存储到 struct 中的次数。如何使 p 成为包含 struct (string name,x,y) 元素的数组?
  • @VasilisNakos 我认为您错过了@IrAM 评论的重点。 &amp;*N 是语法错误。

标签: c struct memory-management malloc dynamic-memory-allocation


【解决方案1】:

要使程序正常运行,您需要做三件事:

  1. 分配N个城市
  2. 对于每个城市,在读取名称之前为名称分配内存
  3. 正确终止名称(分配空字符,而不是字符串)

以下是更正后的代码:

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 不会失败。您可能还需要一个释放分配内存的函数。

【讨论】:

    【解决方案2】:

    要求输入包含即将到来的数据的总计数通常是一个糟糕的设计选择,并且很容易删除该要求。例如:

        #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;                                                                  
        }  
    

    【讨论】:

    • 涉及 void 指针的指针算法未定义。
    • @AugustKarlstrom 谢谢!我知道那个函数有点臭。已更改为char *
    【解决方案3】:

    这个可以工作:

    //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 以节省内存空间。

    【讨论】:

      猜你喜欢
      • 2021-07-17
      • 1970-01-01
      • 2011-08-24
      • 1970-01-01
      • 2020-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多