繁体   English   中英

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

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

我正在尝试从 /proc/cpuinfo 文件中检索信息。 我已经使用 sscanf 检索了 cpu 核心的数量。

现在我试图以类似的方式检索模型名称,但这次我 sscanf 不起作用,因为模型名称是一个包含空格的字符串。

有什么办法可以找回吗?

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;
}

proc/cpuinfo 文件看起来像这样:

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

模型名称的终止条件是“直到行尾”。 大概ReadTextLine读取整行。 因此,您只需要找到模型名称的开头并将其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);
}

但是请注意,您的代码在未初始化的情况下使用cpu_model ,这是一个错误。 您应该将其转换为参数以便调用者为您提供缓冲区,或者使用cpu_model = strdup(match)在堆上分配结果。

正如@bruno 指出的,您还在初始化之前使用了r 正确的条件是:

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

这样您在获得EOF时立即退出并且根本不需要r

cpu_model永远不会被初始化,所以该行:

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

没有地方可以存储数据。 (也就是说,它试图写入cpu_model当前指向的任何cpu_model ,这很可能不是有效的内存位置。)

最简单的解决方法是将声明更改为:

char cpu_model[128];

(并适当地将格式字符串限制为%127s

事实上,当您以未定义的行为进入循环时,您使用r未初始化,因此在不知道ReadTextLine的定义的情况下很难找到您的问题。

另一个答案谈到了一些可能的问题。

这是一个做这项工作的建议:

#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;
}

编译和执行:

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 $ 

在我的情况下, /proc/cpuinfos 的开头是:

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

如果你真的想要一个函数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