不使用 realloc 动态扩展 C 代码

Dynamically expanding C code without using realloc

我需要将文本中用逗号分隔的名称放入动态扩展的结构中,但我被禁止使用 realloc ()。我在这段代码中遇到核心转储错误。这段代码有什么错误?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct movie{

    double budget;
    int genre;
    char* name;
    double score;
    int year;
};


void recorder_function(struct movie *movies){

    FILE*fp;
    fp=fopen("Movies.txt","r");
    struct movie *p;
    int i,n=0;
    char line[1000];
    char temp_budget[50];
    char temp_name[50];
    char temp_genre[50];
    
    while (!feof(fp)) {
    
        fgets(line,1000,fp);
        sscanf(line,"%50[^,],%50[^,],%50[^,]",temp_budget,temp_genre,temp_name);
        
//I open the fields in this section

        movies=(struct movie *)calloc(n+1,sizeof(struct movie));
        p=(struct movie *)calloc(n+1,sizeof(struct movie));
        
        p[n].name=(char*)malloc(sizeof(char)*(strlen(temp_name)+1));
        movies[n].name=(char*)malloc(sizeof(char)*(strlen(temp_name)+1));

        for(i=0;i<n;i++)
        movies[i]=p[i];

        strcpy(movies[n].name,temp_name);

        free(p);
            
        p=movies;

        n++;
        
    }

    for(i=0;i<n;i++)
        printf("%s\n",movies[i].name);
        

}

int main(){

    int choice;
    struct movie *movies;
    recorder_function(movies);
}
   

用新分配的干净缓冲区覆盖指针 movie 是个坏主意。

相反,你应该

  1. 仅为p分配新缓冲区。
  2. 将新元素放入p[n]
  3. 将现有元素 movie[0], ... , movie[n-1] 放入 p[0], ... , p[n-1]
  4. 释放旧缓冲区movie
  5. 将新缓冲区 p 分配给 movie

不要忘记初始化movie以免在第一次释放时造成麻烦。

此外 while (!feof(fp))wrong,您应该在尝试读取之后和使用读取的内容之前检查读取是否成功。

更重要的一点是,您应该确保fopen()成功。将 NULL(失败时 fopen() returns)传递给其他文件操作函数可能会导致麻烦。

另一点是用于 sscanf() 输出的数组应该有一个更多的元素作为终止空字符。

还有一点就是malloc()家族的选角结果是considered as a bad practice.

试试这个:

void recorder_function(struct movie *movies){

    FILE*fp;
    fp=fopen("Movies.txt","r");
    if(fp==NULL){
        fputs("file open error\n", stderr);
        return;
    }
    struct movie *p;
    int i,n=0;
    char line[1000];
    char temp_budget[51];
    char temp_name[51];
    char temp_genre[51];
    
    movies=NULL;
    
    while (fgets(line,1000,fp)) {
    
        sscanf(line,"%50[^,],%50[^,],%50[^,]",temp_budget,temp_genre,temp_name);
        
//I open the fields in this section

        p=calloc(n+1,sizeof(struct movie));
        
        p[n].name=malloc(sizeof(char)*(strlen(temp_name)+1));
        strcpy(p[n].name,temp_name);

        for(i=0;i<n;i++){
            p[i]=movies[i];
        }

        free(movies);

        movies=p;

        n++;
        
    }

    for(i=0;i<n;i++){
        printf("%s\n",movies[i].name);
    }

}

下一阶段将修复参数 movie 的奇怪用法。 C 中的参数是所传递内容的 副本 ,被调用函数中参数的修改不会影响调用者中传递的内容。您的选择是:

  • 删除参数 movies 并将其转换为局部变量。
  • recorder_function 获取指向 struct movie* (struct movie**) 的指针,并让它使用指针修改调用者指定的内容。 (在这种情况下,您还必须更改调用函数以传递指针的语句)