1

我是 C 的新手,并试图实现 whoami,作为对自己的练习。我有以下代码:

#define _POSIX_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h> // strtok

int str_to_int(const char *str)
{
    int acc = 0;
    int i;
    for (i = 0; str[i] != '\0'; ++i) {
        acc = (10 * acc) + (str[i] - 48); // 48 -> 0 in ascii
    }
    return acc;
}

int main()
{
    FILE *passwd;
    char *line = NULL;
    size_t line_size;

    passwd = fopen("/etc/passwd","r");

    uid_t uid = getuid();

    while (getline(&line, &line_size,passwd) != -1) {
        char *name = strtok(line,":");
        strtok(line,":"); // passwd
        char *user_id = strtok(line,":");
        if (str_to_int(user_id) == uid) {
            printf("%s\n",name);
            break;
        }
    }

    fclose(passwd);
    return 0;
}

我是否需要将行指针保存在 while 循环内。因为我认为strtok会以某种方式对其进行修改,但是我不确定在将其与strtok一起使用之前是否需要复制该行或该行的起始地址。

4

3 回答 3

1

strtok是一个可怕的功能。我不知道您阅读了哪些文档(如果有的话?),但它既修改了传递的缓冲区,又保留了指向缓冲区的内部指针;您应该只在一次在给定行上使用缓冲区时传递缓冲区,然后再传递,NULL以便它知道从中断的地方开始而不是从头开始(实际上它不会很好地工作,因为它踩到了缓冲区...)。

更好的是,找到一些其他的方式来解析并远离strtok.

于 2012-04-11T19:44:45.110 回答
0

使用它可能更安全strtok_r。在多线程情况下更安全。这可能不适用于这种情况,但有时最好假设您编写的任何片段都可能最终出现在多线程应用程序中。以下是修改后使用的 OP 代码strtok_r

  char *pos;
  char *name = strtok_r(line,":",&pos);
  strtok_r(NULL,":",&pos); // passwd
  char *user_id = strtok_r(NULL,":",&pos);

而且,是的,strtok(和strtok_r)确实修改了给定的输入缓冲区(第一个参数)。但如果使用得当,它是安全的。由于strtok返回一个指向给定字符串内的缓冲区的指针,因此您需要注意如何使用它。在您的情况下,当它跳出循环时,nameuser_id指向line缓冲区内的一个值。

您也许应该阅读getline. 您使用它的方式,它返回一个分配的缓冲区,您的应用程序负责释放该缓冲区。这可能是您的目标,但我提到它是因为我在发布的代码中没有看到free对它的调用。

于 2012-04-11T20:12:50.550 回答
0

我完全同意 geekosaur(和 Mark)的观点。套用他的评论,你可以修改上面的代码如下:

while (getline(&line, &line_size, passwd) != -1) {
    char *name = strtok(line,":");
    strtok(NULL,":"); // passwd
    char *user_id = strtok(NULL,":");
    if (str_to_int(user_id) == uid) {
        printf("%s\n",name);
        break;
    }
}

strtok您应该为除第一个以外的调用传递 NULL 。

于 2014-11-30T21:38:09.900 回答