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
您的模型名称的终止条件是"till the end of the line"。大概 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
时立即退出。
事实上,当您以未定义的行为进入循环时,您使用 r 未初始化,如果不知道 [=26 的定义,很难找到您的问题=]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;
}
cpu_model
从未初始化,所以行:
sscanf (match, "model name : %s", cpu_model);
没有地方可以存储数据。 (也就是说,它正在尝试写入 cpu_model
当前指向的任何位置,这很可能不是有效的内存位置。)
最简单的解决方法是将声明更改为:
char cpu_model[128];
(并适当限制格式字符串为%127s
)
我正在尝试从 /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
您的模型名称的终止条件是"till the end of the line"。大概 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
时立即退出。
事实上,当您以未定义的行为进入循环时,您使用 r 未初始化,如果不知道 [=26 的定义,很难找到您的问题=]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;
}
cpu_model
从未初始化,所以行:
sscanf (match, "model name : %s", cpu_model);
没有地方可以存储数据。 (也就是说,它正在尝试写入 cpu_model
当前指向的任何位置,这很可能不是有效的内存位置。)
最简单的解决方法是将声明更改为:
char cpu_model[128];
(并适当限制格式字符串为%127s
)