Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 读/写程序_C - Fatal编程技术网

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();
...