[英]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.