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



我正在尝试从/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 filen"); 
return 0;
} 
while( r != EOF){
r = ReadTextLine(fp, buffer, BUFFER_SIZE);
//    printf("%d %sn", 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当前指向的任何位置,这很可能不是有效的内存位置。(

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

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

相关内容

  • 没有找到相关文章

最新更新