1

好的,所以我有下面的代码,我只是从文件中提取各种东西并将它们输入到一个结构数组中,它“似乎”最初可以工作,但是当我在完成文件后去打印它似乎已经用最后一个值替换了所有课程和名称,奇怪的是整数(成绩)不会发生这种情况,成绩确实被正确输入。

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

struct student {
    char *name;
    char *course;
    int grade;

};

void courseSort(struct student d[20], int size);

int main(void)
{
    FILE* fp;
    char* filename = "grades.csv";
    char buffer[100];
    char* name, *class;
    char* del=",";
    int grade, i, counter=0;

    struct student d[20];

    if((fp=fopen(filename, "r"))==NULL)
    {
        printf("unable to open %s\n", filename);
        exit(1);
    }

    while(fgets(buffer, sizeof(buffer), fp) !=NULL)
    {
        name = strtok(buffer,del);
        class=strtok(NULL,del);
        grade = atoi(strtok(NULL,del));

        d[counter].name=name;
        d[counter].course=class;
        d[counter].grade=grade;
        printf("%s    %s       %d\n",d[counter].name,d[counter].course,d[counter].grade);
        counter++;
    }

    printf("\n\n\n");

    for(i=0;i<counter;i++)
        printf("%s    %s     %d\n",d[i].name,d[i].course,d[i].grade);
    courseSort(d,counter);

    fclose(fp);
 }

我不确定我做错了什么:(这一切看起来都很简单,但不确定为什么它只是用最新的替换所有内容。

4

3 回答 3

4

返回一个指向缓冲区的strtok指针并且不分配内存。由于您不复制字符串,因此最终会得到大量指向同一缓冲区的指针,该缓冲区在循环的每次迭代中都会被覆盖。

要解决此问题,您需要更改循环以使用以下方式复制字符串strdup

while(fgets(buffer, sizeof(buffer), fp) != NULL)
{
    d[counter].name = strdup(strtok(buffer, del));
    d[counter].course = strdup(strtok(NULL, del));
    d[counter].grade = atoi(strtok(NULL, del));
    counter++;
}

free一旦不再需要字符串,不要忘记返回分配的内存:

for (i = 0; i < counter; i++) {
   free(d[i].name);
   free(d[i].course);

   d[i].name = NULL;
   d[i].course = NULL;
}

请注意,这strdup是 POSIX1.2001 标准的一部分,而不是 C89 的一部分。如果它不可用,您将不得不自己重新实现它(很容易):

char *my_strdup(const char *str) {
  char *copy;
  size_t len = strlen(str) + 1;
  if (len == 0) return NULL;
  copy = (char *)malloc(len);
  if (copy == NULL) return NULL;
  memcpy(copy, str, len);
  return copy;
}
于 2013-07-13T21:20:54.470 回答
1

错误就在这里。

d[counter].name=name;

用。。。来代替:

d[counter].name = strdup(name); /*don't forget to free this memory.*/

课程的问题是一样的。

于 2013-07-13T21:20:26.617 回答
1

这是对指针和字符数组(字符串)的简单误解。这里有几页很好地解释了它们:

在您的情况下,您将结构指针值设置为等于从 strtok 返回的指针。许多字符串函数通过将结果放在某个内存地址并返回指向它的指针来工作。返回的指针始终相同,因此所有结构值都将指向 strtok 调用的最后一个结果。

这就是您需要strdup(字符串重复)的原因。基本上,它获取给定地址的值并将内容复制到内存中的新位置并返回该值。

于 2013-07-13T21:29:57.620 回答