我是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 回答
使用
strtok_r
可能更安全 . 在多线程情况下更安全 . 这可能不适用于这种情况,但有时更好的只是假设您编写的任何片段可能最终出现在多线程应用程序中 . 以下是修改为使用strtok_r
的OP代码 .并且,是的,
strtok
(和strtok_r
)会修改给定的输入缓冲区(第一个参数) . 但如果使用得当它可以是安全的 . 由于strtok
返回指向给定字符串内缓冲区的指针,因此您需要小心如何使用它 . 在您的情况下,当它突然出现循环时,name
和user_id
将指向line
缓冲区内的值 .你可能应该阅读getline的手册页 . 您使用它的方式,它返回一个分配的缓冲区,您的应用程序负责释放 . 这可能是你的目标,但我提到它是因为我没有在发布的代码中看到它的
free
调用 .我完全同意geekosaur(和马克) . 解释他的评论,你可以修改上面的代码如下:
除了第一个调用之外,您应该为
strtok
调用传递NULL .strtok
是一个可怕的功能 . 我不知道你读了什么文件(如果有的话?)但它都修改了它传递的缓冲区并保留了一个内部指针进入缓冲区;你应该只在你第一次在给定的线上使用缓冲区时传递缓冲区,然后传递NULL
,这样它就知道从它停止的地方开始而不是从头开始(实际上它不会正常工作,因为它踩踏了在缓冲区...) .更好,找到一些其他解析方法,并远离
strtok
.