为了更好地解释它,我有一个结构“用户”,其中包含用户ID,他们的名字以及带有他们朋友ID的数组。循环读取文件作为输入,其中每行包含有关用户的信息,在此模型中:“ID; name; friendsID”,用户可能有多个朋友(在这种情况下,它是“ID; name; friendID1 ; ...; friendIDx“)。
我尝试读取每个用户的每一行,计算多少“;”要知道用户有多少朋友,并使用strtok获取用户ID,姓名和朋友的ID。一切都有效,除了名字。它正确地读取每个名称,但不知何故,吃了循环的结束,每个用户都有相同的名字,读取的姓氏。
我不知道为什么它会这样做,如果它在循环内正确读取和分配名称字符串。
这是我到目前为止所得到的:
typedef struct user {
int ID;
char* name;
int* friendsID;
};
// declaring variables, declaring user array, opening file, allocating memory, etc.
for(i = 0; i < num_users; i++){
fgets(line, sizeof(line), input); // Reads a line
for(j = 0, user_friends = 0; line[j]; j++) { // Counts how many friends the user has
user_friends += (line[j] == ';');
}
user[i].ID = atoi(strtok(line, ";")); // Reads the ID
user[i].name = strtok(NULL, ";"); // Reads the name
for(k = 0; k < user_friends - 1; k++) { // Reads the friend's IDs
user[i].friendsID[k] = atoi(strtok(NULL, ";"));
}
}
最后,我拥有所有正确的ID和朋友的ID,但名字都是一样的。
答案 0 :(得分:0)
在许多方面,代码可能会调用未定义的行为。首先,只是一个nit,但*
与变量一致,而不是类型,例如:
typedef struct user {
int ID;
char *name;
int *friendsID;
};
这通常可以防止声明:
int* a, b, c; /* b and c are NOT pointers */
在您的代码中,如果您愿意,可以对';'
strtok
进行硬编码,但是您可以更好地创建一个常量或变量来保存分隔符,如果你需要调整它,你只能在一个地方进行调整。
请注意,由于您同时拥有name
和friendsID
,因此它们都是未初始化的指针,并且没有多个字符或整数的存储空间。您必须为要存储的任何字符串或整数数组动态分配存储空间。
不需要for (i = 0; i < num_users; i++)
。正如您所解释的那样,每行上有user
的一组数据,所以只需读取所有行,除非您绝对需要将读取限制为特定行数。如果您想要阅读所有行,只需要一个简单的while (fgets (line, sizeof line, input))
。
正如评论中所提到的,如下所示,您需要验证从线上获取的每个读取和每个标记。最简单的方法是 检查返回 ,就像您应该对每个函数调用一样。
如果您有friendsID
存在,您需要一种方法(1)测试是否存在,以及(2)根据需要分配/重新分配,直到所有内容都被读取。以下是基于发布的有限信息解决您的问题的一种方法。它使用idx
作为user
索引,使用fidx
作为friendsID
索引(我不是那个广告素材)。将各个部分组合在一起,您可以执行以下操作。通读代码段并查看逻辑的结构。 (注意:这只是一个例子,没有发布任何数据)如果您有任何疑问,请告诉我。
char *delim = ";\n";
int idx = 0, fidx = 0, nfriends = 10;
/* line must be declared as a character array (not pointer) to use sizeof
* (only add record if both ID and name present)
*/
while (fgets (line, sizeof line, input)) {
char *p = strtok (line, delim);
if (p) /* valid token for ID? */
user[idx].ID = atoi (p);
else {
/* throw error */
continue;
}
if ((p = strtok (NULL, delim))) /* valid token for name? */
user[idx].name = strdup (p);
else {
/* throw error */
continue;
}
if ((p = strtok (NULL, delim))) { /* is there a friendsID? */
/* allocate for nfriends */
user[idx].friendsID = calloc (nfriends, sizeof *(user[idx].friendsID));
if (!user[idx].friendsID) {
/* memory exhausted, throw error */
break;
}
user[idx].friendsID[fidx++] = atoi (p); /* assign 1st ID */
while ((p = strtok (NULL, delim))) { /* loop for all remaining */
user[idx].friendsID[fidx] = atoi (p);
if (fidx++ == nfriends) { /* check against limit */
/* realloc user[idx].friendsID to
* 2 * nfriends * sizeof *(user[idx].friendsID)
* nfriends *= 2
*/
}
}
/* optional -- realloc user[idx].friendsID to
* fidx * sizeof *(user[idx].friendsID) for exact size
*/
}
idx++; /* increment user index */
}