解析程序:分段错误(核心已转储)

5

我正在编写一个程序,将读取文件/proc/stat并解析每一行,将其存储为令牌,最终处理后表示在输出表中。 我已经能够使程序解析该程序,但是当存储令牌在各种数组值中时,我遇到了错误:Segmentation fault(core dumped)。 我不确定是什么原因导致这个问题,因为我已经分配了内存。 我也是一个初学者,对于C语言不是很熟悉。

//standard input/output file to help with io operations
#include<stdio.h>
//standard library files to help with exit and other standard functions
#include<stdlib.h>
//header file for usleep function
#include <unistd.h>
#include <string.h> //header file for strtok function

int main()
{
//FILE pointer will need to be declared initially, in this example the name is fp
FILE *fp;
//A character pointer that will store each line within the file; you will need to parse this line to extract useful information
char *str = NULL;
//size_t defined within C is a unsigned integer; you may need this for getline(..) function from stdio.h to allocate buffer dynamically
size_t len = 0;
//ssize_t is used to represent the sizes of blocks that can be read or written in a single operation through getline(..). It is similar to size_t, but must be a signed type.
ssize_t read;
float cpu_line1[4];
float cpu_line2[4];
float cpu_line3[4];
float cpu_line4[4];
float cpu_line5[4];
float page[2];
float swap[2];
float intr;
float ctxt;
float btime;


//a variable declared to keep track of the number of times we read back the file
unsigned int sample_count = 0;

//opening the file in read mode; this file must be closed after you are done through fclose(..); note that explicit location of the file to ensure file can be found
fp = fopen("/proc/stat", "r");

//checking if the file opening was successful; if not we do not want to proceed further and exit with failure code right away
if(fp == NULL)
{
    exit(EXIT_FAILURE);
}
int i = 0;
char **string = NULL; //declaration of string
string = (char**)malloc(10*sizeof(char*)); //assign space for 10 pointers to array
for (i=0; i<10; i++) //allocate 50 bytes to each string in the array
{
    string[i] = (char*)malloc(50*sizeof(char));
}
char *s = NULL;

//a loop that will read one line in the file at a time; str will read the line; len will store the length of the file
while(1)
{
    printf("\e[1;1H\e[2J"); //this line will make sure you have cleared the previous screen using C's powerful format specifiers
    printf("----------------------------------------------------------------\n");//used for presentation
    printf("Sample: %u\n", sample_count); //showing the sample count
    int i = 0; //counter

    while ((read = getline(&str, &len, fp)) != -1)
    {
       // printf("Retrieved line: \n%sof length: %zu, allocated buffer: %u :\n", str, read, (unsigned int) len);

        s = strtok(str, " ");
        printf("Test program: %s\n", s);
    }

    if (i=0)
    {
        sprintf(string[0], s);
        cpu_line1[0] = atoi(strtok(NULL, " "));
        cpu_line1[1] = atoi(strtok(NULL, " "));
        cpu_line1[2] = atoi(strtok(NULL, " "));
        cpu_line1[3] = atoi(strtok(NULL, " "));
    }

    if (i=1)
    {
        sprintf(string[1], s);
        cpu_line2[0] = atoi(strtok(NULL, " "));
        cpu_line2[1] = atoi(strtok(NULL, " "));
        cpu_line2[2] = atoi(strtok(NULL, " "));
        cpu_line2[3] = atoi(strtok(NULL, " "));
    }

    if (i=2)
    {
        sprintf(string[2], s);
        cpu_line3[0] = atoi(strtok(NULL, " "));
        cpu_line3[1] = atoi(strtok(NULL, " "));
        cpu_line3[2] = atoi(strtok(NULL, " "));
        cpu_line3[3] = atoi(strtok(NULL, " "));
    }

    if (i=3)
    {
        sprintf(string[3], s);
        cpu_line4[0] = atoi(strtok(NULL, " "));
        cpu_line4[1] = atoi(strtok(NULL, " "));
        cpu_line4[2] = atoi(strtok(NULL, " "));
        cpu_line4[3] = atoi(strtok(NULL, " "));
    }

    if (i=4)
    {
        sprintf(string[4], s);
        cpu_line5[0] = atoi(strtok(NULL, " "));
        cpu_line5[1] = atoi(strtok(NULL, " "));
        cpu_line5[2] = atoi(strtok(NULL, " "));
        cpu_line5[3] = atoi(strtok(NULL, " "));
    }

    if(i=5)
    {
        sprintf(string[5], s);
        page[0] = atoi(strtok(NULL, " "));
        page[1] = atoi(strtok(NULL, " "));
    }

    if(i=6)
    {
        sprintf(string[6], s);
        swap[0] = atoi(strtok(NULL, " "));
        swap[1] = atoi(strtok(NULL, " "));
    }

    if(i=7)
    {
        sprintf(string[7], s);
        intr = atoi(strtok(NULL, " "));
    }

    if(i=8)
    {
        sprintf(string[8], s);
        ctxt = atoi(strtok(NULL, " "));
    }

    if(i=9)
    {
        sprintf(string[9], s);
        btime = atoi(strtok(NULL, " "));
    }

    printf("----------------------------------------------------------------\n"); //used for presentation
    usleep(500000);//this will ensure time delay
    rewind(fp);//rewind the file pointer to start reading from the beginning
    sample_count++;//update the sample count
}
//Frees pointers to make program memory efficient
free(str);
for (i=0; i <10; i++)
{
    free(string[i]);
}
//once you are done, you should also close all file pointers to make your program memory efficient
fclose(fp);


return 0;

编辑

以下是在Cygwin中运行该程序的副本。


示例:0

测试程序:cpu

测试程序:cpu0

测试程序:cpu1

测试程序:cpu2

测试程序:cpu3

测试程序:page

测试程序:swap

测试程序:intr

测试程序:ctxt

测试程序:btime

分段错误(核心已转储)


你在尝试使用sprintf语句做什么?如果你想将s的内容复制到string[i]中,你应该使用strcpy函数。在sprintf中,第二个参数是格式化字符串,根据其中的内容,可能会发生不好的事情。 - Hellmar Becker
启用编译器警告(= !)。 - Karoly Horvath
1
这是很多代码,哪里发生了崩溃?在哪些情况下?输入是什么?当崩溃发生时涉及的变量值是什么?你有编译器警告吗?如果启用更多警告,会发生什么? - Some programmer dude
@HellmarBecker sprintf有什么问题吗? - ameyCU
@JoachimPileborg,基本上程序成功打印了测试语句,没有编译器警告。之后程序崩溃了。 - J Hall
如果参数2包含%字符,则会将其解释为格式,以在其后包括某个参数(该参数不存在)。这将访问未初始化的内存,可能导致段错误。 - Hellmar Becker
3个回答

3

不确定为什么会出现“分段错误(Segmentation fault)”,但我可以告诉你,如果你写了以下代码:

if (i=0) //it means assign the value 0 to i and if the value would be different from zero, follow the "then" branch
if (i==0) //is compare i to 0 and if true follow the "then" branch

如果有错误,请纠正。

希望这可以帮助你 :)


谢谢。我已经尝试了这个方法,但仍然出现错误,不过感谢您的帮助。 - J Hall

3

除其他事项外,您的条件不正确:

if (i = 1) {
    // do something.
}

这将值1分配给i,而不是与1进行比较。尝试使用条件i == 1


谢谢。我已经更改了,但是我仍然收到相同的消息。这是在Cygwin中运行时输出的副本-------------------------------------------------- ------------------------------ 示例:0 测试程序:cpu 测试程序:cpu0 测试程序:cpu1 测试程序:cpu2 测试程序:cpu3 测试程序:页面 测试程序:交换 测试程序:intr 测试程序:ctxt 测试程序:btime 分段错误(核心已转储) - J Hall

1
如其他答案所述,您应该将if(i=0)替换为if(i==0)
因为strtok()返回NULL,所以您会得到一个分段错误,atoi()将NULL作为参数。
    cpu_line1[0] = atoi(strtok(NULL, " "));
    cpu_line1[1] = atoi(strtok(NULL, " "));
    cpu_line1[2] = atoi(strtok(NULL, " "));
    cpu_line1[3] = atoi(strtok(NULL, " "));

只要有足够的标记可以解析,此代码就能正常工作。但似乎你试图过于频繁地获取下一个标记。

在将其传递给atoi()之前,应检查strtok()的返回值是否为NULL。我建议使用循环简化您的代码,并将检查NULL应用于每个使用atoi()的地方。

这里是一个检查的简单示例:

char* token = strtok(NULL, " ");
if(token != NULL)
    cpu_line1[0] = atoi(token);

如果您在每个strtok()调用中添加检查,这应该可以解决您的分段错误问题。

非常感谢,我的朋友。 - J Hall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接