我正在尝试编写一个具有获取进程详细信息的函数的脚本。
到目前为止我已经
了#include <stdio.h>
#include <string.h>
#include <ctype.h>
char* getField(FILE* file, char* prop, int len){
char line[100], *p;
while(fgets(line, 100, file)) {
if(strncmp(line, prop, len) != 0)
continue;
p = line + len + 1;
while(isspace(*p)) ++p;
break;
}
return p;
}
int main(int argc, char *argv[]) {
char tgid[40], status[40], *s, *n;
FILE* statusf;
printf("Please Enter PID\n");
if (fgets(tgid, sizeof tgid, stdin)) {
//Remove new line
strtok(tgid, "\n");
snprintf(status, 40, "/proc/%s/status", tgid);
statusf = fopen(status, "r");
if(!statusf){
perror("Error");
return 0;
}
s = getField(statusf, "State:", 6);
n = getField(statusf, "Name:", 5);
printf("State: %s\n", s);
printf("Name: %s\n", n);
}else{
printf("Error on input");
}
fclose(statusf);
return 1;
}
我仍然发现指针和记忆有点模糊。当我在没有
的情况下运行此脚本时n = getField(statusf, "Name:", 5);
我得到正确的输出(例如S - 睡觉);
但是当我调用函数来获取进程名称时,我似乎也得到了同样的结果,例如。
状态:ntary_ctx 名称:ntary_ctx
这甚至都不是正确的名字。我认为问题必须是函数变量保持价值。但我认为当一个函数返回其内存然后弹出堆栈。
答案 0 :(得分:4)
代码重新调整指向局部变量的指针
这是无效的 - 它是未定义的行为(UB)。 @stark
这解释了&#34;我似乎得到了两个&#34;同样的输出,因为一个可能的UB是重复使用相同的缓冲区。另一种可能性是代码崩溃,以及其他候选者。
// Bad code
char* getField(FILE* file, char* prop, int len){
char line[100], *p;
...
p = line + len + 1;
...
return p; // `p` points to `line[]`
}
代码需要复制。可以通过分配或传入目的地来完成此操作,如下所示。
char* getField(FILE* file, char *dest, const char* prop, int len){
if (problem) return NULL;
...
return strcpy(dest, p);
}
// Example call
char prop_state[100];
if (getField(statusf, prop_state, "State:", 6)) Success();
else Handle_Problem();
...
char prop_name[100];
if (getField(statusf, prop_name, "Name:", 6)) Success();
...
更好的代码会传递dest
的大小,因此getField()
可以处理
char* getField(FILE* file, char *dest, size_t size, const char* prop, int len){
...
if (strlen(p) >= size) return NULL; // Not enough room
return strcpy(dest, p);
}
// usage
if (getField(statusf, prop_state, sizeof prop_state, "State:", 6)) Success();
...
答案 1 :(得分:1)
一个问题是,在WHERE
中,您正在返回getField()
,这是指向p
的指针加上一些偏移量。但是line
是该函数中的局部变量,因此当函数终止时它超出了范围。 The answer是一个很好的解释。
作为第一步,你可以让它line
在函数返回后被允许使用指针,但是第二个调用仍会覆盖你通过第一次调用读取的内容。
因此,最好的方法是为值传递一个额外的缓冲区:
static char line[100]
并且在main()中你将有两个不同的缓冲区
char* getField(FILE* file, char* prop, int len, char *value){
char line[100], *p; // now it's ok
... // everything at it is now before return
strcpy( value, p );
return value;
}
答案 2 :(得分:0)
如果您使用该方法,则需要在每次读取字段时关闭并重新打开文件,或者在leat倒带到开头时重新打开文件。它不是编写C输入文件解析器的好方法,但它可用于短文件和快速程序。