在一个循环中,读取的不同字符串最后重复为相同的字符串

时间:2016-10-12 02:05:37

标签: c string strtok

为了更好地解释它,我有一个结构“用户”,其中包含用户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,但名字都是一样的。

1 个答案:

答案 0 :(得分:0)

在许多方面,代码可能会调用未定义的行为。首先,只是一个nit,但*与变量一致,而不是类型,例如:

typedef struct user {
    int ID;
    char *name;
    int *friendsID;
};

这通常可以防止声明:

int* a, b, c;    /* b and c are NOT pointers */

在您的代码中,如果您愿意,可以对';' strtok进行硬编码,但是您可以更好地创建一个常量或变量来保存分隔符,如果你需要调整它,你只能在一个地方进行调整。

请注意,由于您同时拥有namefriendsID,因此它们都是未初始化的指针,并且没有多个字符或整数的存储空间。您必须为要存储的任何字符串或整数数组动态分配存储空间。

不需要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 */
}