简体   繁体   English

c 中带有空格的 sscanf 字符串的替代方法?

[英]alternative for sscanf string with spaces in c?

I am trying to retrieve information from /proc/cpuinfo file.我正在尝试从 /proc/cpuinfo 文件中检索信息。 I have retrieved number of cpu core using sscanf.我已经使用 sscanf 检索了 cpu 核心的数量。

Now I am trying to retrieve model name similarly but I sscanf is not working this time because model name is a string including spaces.现在我试图以类似的方式检索模型名称,但这次我 sscanf 不起作用,因为模型名称是一个包含空格的字符串。

Is there any alternative to retrieve it?有什么办法可以找回吗?

char *get_cpu_model()
{
   int fp;
   int r;
   char* match;
   char *cpu_model;

   /* Read the entire contents of /proc/cpuinfo into the buffer. */
   fp = open("/proc/cpuinfo",O_RDONLY);

    if (fp == -1) 
   {   
       printf("Error! Could not open file\n"); 
       return 0;
   } 
    while( r != EOF){

       r = ReadTextLine(fp, buffer, BUFFER_SIZE);
    //    printf("%d %s\n", buffer_size, buffer);
       match = strstr (buffer, "model name");

       if (match !=NULL){
            /* Parse the line to extract the clock speed. */
            sscanf (match, "model name : %s", cpu_model);
            break;
       }
   }
   close(fp);

   return cpu_model;
}

The proc/cpuinfo file looks something like this: proc/cpuinfo 文件看起来像这样:

processor:0
cpu core :1
model name: Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz

Your termination condition for the model name is "till the end of the line".模型名称的终止条件是“直到行尾”。 Presumably ReadTextLine reads the entire line.大概ReadTextLine读取整行。 So all you need is to find the beginning of the model name and strcpy it out of there:因此,您只需要找到模型名称的开头并将其strcpy

match = strstr(buffer, "model name: ");
// ... match points to "model name: XXX"
if(match) {
    match += strlen("model name: ");
    // ... match points to "XXX"
    strcpy(cpu_model, match);
}

Note, however, that your code is using cpu_model without initializing it, which is a bug.但是请注意,您的代码在未初始化的情况下使用cpu_model ,这是一个错误。 You should either convert it to a parameter so that the caller would give you the buffer, or use cpu_model = strdup(match) to allocate the result on the heap.您应该将其转换为参数以便调用者为您提供缓冲区,或者使用cpu_model = strdup(match)在堆上分配结果。

As @bruno noted you're also using r before it's initialized.正如@bruno 指出的,您还在初始化之前使用了r The correct condition would be:正确的条件是:

while(ReadTextLine(fp, buffer, BUFFER_SIZE) != EOF)

so that you exit immediately when you get EOF and don't need r at all.这样您在获得EOF时立即退出并且根本不需要r

cpu_model is never initialized so the line: cpu_model永远不会被初始化,所以该行:

sscanf (match, "model name : %s", cpu_model);

doesn't have anywhere to store the data.没有地方可以存储数据。 (That is, it is trying to write to wherever cpu_model is currently pointing, which is most likely not a valid memory location.) (也就是说,它试图写入cpu_model当前指向的任何cpu_model ,这很可能不是有效的内存位置。)

The easiest fix would be to change the declaration to:最简单的解决方法是将声明更改为:

char cpu_model[128];

(and appropriately restrict the format string to be %127s ) (并适当地将格式字符串限制为%127s

Out of the fact you use r non initialized when you enter in the loop with an undefined behavior, it is difficult to find your problem without knowing the definition of ReadTextLine .事实上,当您以未定义的行为进入循环时,您使用r未初始化,因此在不知道ReadTextLine的定义的情况下很难找到您的问题。

The other answer speak about some possibile problems.另一个答案谈到了一些可能的问题。

Here is a proposal to do the work :这是一个做这项工作的建议:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

char * get_cpu()
{
  FILE * fp = fopen("/proc/cpuinfo", "r");
  char line[256];
  char * result = NULL;

  if (fp == NULL) {
    /* low probability to happen */
    perror("cannot read /proc/cpuinfo");
    return NULL;
  }

  while (fgets(line, sizeof(line), fp) != NULL) {
    char * match = strstr(line, "model name");

    /* bypass ':' then possible spaces */
    if ((match != NULL) && ((match = strchr(match, ':')) != NULL)) {
      do
        match += 1;
      while (*match && isspace((unsigned char) *match));

      if (*match) {
        /* remove possible spaces including \r\n at end of line */
        char * pend = match + strlen(match);

        while (isspace((unsigned char) *--pend))
          *pend = 0;

        /* duplicate the string to not return an address in the stack */
        result = strdup(match);
        break;
      }
    }
  }

  fclose(fp);
  return result;
}

int main()
{
  char * s = get_cpu();

  if (s != NULL) {
    printf("(first) cpu is '%s'\n", s);
    /* the result was allocated, free it when not needed anymore */
    free(s);
  }

  return 0;
}

Compilation and execution :编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall -Werror -pedantic c.c
pi@raspberrypi:/tmp $ ./a.out
(first) cpu is 'ARMv7 Processor rev 3 (v7l)'
pi@raspberrypi:/tmp $ 

In my case the beginning of /proc/cpuinfos is :在我的情况下, /proc/cpuinfos 的开头是:

pi@raspberrypi:/tmp $ head -2 /proc/cpuinfo
processor   : 0
model name  : ARMv7 Processor rev 3 (v7l)
pi@raspberrypi:/tmp $ 

If you really want to have a function ReadTextLine it must do more than just a fgets , so let decide it also remove the spaces at the end of the line (it is useless to move spaces at the beginning of the line in this context)如果你真的想要一个函数ReadTextLine它必须做的不仅仅是一个fgets ,所以让我们决定它也删除行尾的空格(在这种情况下移动行首的空格是没用的)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

char * ReadTextLine(FILE * fp, char * line, int size)
{
  if (fgets(line, size, fp) == NULL)
    return NULL;

  /* remove possible spaces including \r\n at end of line */
  char * pend = line + strlen(line);

  while ((pend != line) && isspace((unsigned char) *--pend))
    *pend = 0;

  return line;
}

char * get_cpu()
{
  FILE * fp = fopen("/proc/cpuinfo", "r");
  char line[256];
  char * result = NULL;

  if (fp == NULL) {
    /* probably never happend under linux */
    perror("cannot read /proc/cpuinfo");
    return NULL;
  }

  while (ReadTextLine(fp, line, sizeof(line)) != NULL) {
    char * match = strstr(line, "model name");

    /* bypass ':' then possible spaces */
    if ((match != NULL) && ((match = strchr(match, ':')) != NULL)) {
      do
        match += 1;
      while (*match && isspace((unsigned char) *match));

      if (*match) {
        result = strdup(match);
        break;
      }
    }
  }

  fclose(fp);
  return result;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM