C 读/写程序
我正在尝试编写一个脚本,该脚本具有获取流程详细信息的功能 到目前为止我有C 读/写程序,c,C,我正在尝试编写一个脚本,该脚本具有获取流程详细信息的功能 到目前为止我有 #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)
#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;
}
我得到了正确的输出(如S-睡眠)
但是当我调用函数来获取进程名时,我似乎得到了两个进程的相同输出
州:ntary_ctx
姓名:ntary_ctx
那甚至不是正确的名字。我认为问题一定是函数变量保持其值。但是我认为当一个函数返回它的内存时,它就会从堆栈中弹出 如果使用这种方法,则每次读取字段时都需要关闭并重新打开文件,或者至少要倒带到开始处。对于编写C输入文件解析器来说,这并不是一个好方法,但对于一个短文件和一个快速程序来说,它就足够了。一个问题是,在
getField()
中,您返回的是p
,它是指向行的指针加上一些偏移量。但是line
是该函数中的一个局部变量,因此当函数终止时,它超出范围。这是一个很好的解释
作为第一步,您可以在函数返回后允许使用指针,但第二次调用仍然会覆盖第一次调用读取的内容。
因此,最好的方法是为值传递一个额外的缓冲区:
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;
}
在main()中有两个不同的缓冲区
char name[100], state[100]; // at least same size as line - length of label
....
s = getField(statusf, "State:", 6, state);
n = getField(statusf, "Name:", 5, name);
代码正在重新调整指向局部变量的指针。
这是无效的-它是未定义的行为(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();
...
就语义而言,C程序不是script@rtur谢谢,刚刚换了个名字。我有很多东西要学,先编译所有警告和调试信息(gcc-Wall-g
),然后使用调试器(gdb
)。顺便说一句,读更多关于C(例如),并考虑使用<代码> SCANF来阅读一些<代码> int <代码> PID。@ BaselestalyKevyy谢谢,我真的需要读更多。我倾向于深入研究,这不是正确的方法。问题是关于一个典型的错误,但尊重。啊,好的。是的,这可能是各种各样的错误,我将对正确的C编程实践进行大量研究。通常,您将声明一个包含所有选项的结构,然后编写一个函数,从配置文件填充它。因此,配置文件只读取一次。静态没有帮助,因为他多次调用该函数。@stark oops,你说得对,'我还没有看过这个。我将更正显示多个调用的answerNice答案。getField()
@davidKirwan注意:建议将提示传递到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();
...