在循环中一起使用getline和strtok

时间:2012-04-11 19:38:20

标签: c pointers getline strtok

我是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之前是否需要复制该行或该行的起始地址。

3 个答案:

答案 0 :(得分:1)

strtok是一个可怕的功能。我不知道你读了什么文件(如果有的话?)但它都修改了它传递的缓冲区并保留了一个内部指针进入缓冲区;你只应该在给定的行上使用第一次的时间传递缓冲区,并随后传递NULL,以便它知道从中断的地方继续而不是从头开始(这实际上不会正常工作,因为它踩在缓冲区上......)。

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

答案 1 :(得分:0)

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

  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调用它。

答案 2 :(得分: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。