【问题标题】:Seg Fault Error :11 Known lines with Error [closed]段错误错误:11 已知错误行[关闭]
【发布时间】:2023-03-12 22:22:01
【问题描述】:

我在这段代码中有一个段错误错误,但我不明白为什么。有人可以解释我做错了什么。 我已经评论了我需要在这个函数中做的事情的列表。我以为我做对了,但是当我打印出来时,事实证明实际上正在发生完全不同的事情。

void analyze_file(FILE *file, struct climate_info **states, int num_states) {
    const int line_sz = 100;
    char line[line_sz];
    int currentStates = countStates(states);

    while (fgets(line, line_sz, file) != NULL) 
    {

        char* foundCode = strtok(line, "\t");                   
        int rankOfState = compareOrder(states, foundCode, currentStates);
        if(rankOfState == -1)             
        {

            states[currentStates] = (struct climate_info *) malloc(sizeof(struct climate_info) *num_states);
            strcpy((states[currentStates]) -> code, foundCode);
            states[currentStates] -> num_records=1;

            char* currentTimeStamp = strtok(NULL, "\t");                    
            unsigned long TIMESTAMP;
            sscanf(currentTimeStamp,"%lu", &TIMESTAMP);                        


            char* currentGeol = strtok(NULL, "\t");
            long long GEOL;
            sscanf(currentGeol,"%llu", &GEOL);


            char* currentHumidity = strtok(NULL, "\t");
            double HUMIDITY;
            sscanf(currentHumidity, "%lf",&HUMIDITY);


            char* currentSnow = strtok(NULL, "\t");
            float SNOW;
            sscanf(currentSnow, "%f", &SNOW);


            char* currentCloud = strtok(NULL, "\t");
            double CLOUD;
            sscanf(currentCloud, "%lf",&CLOUD);


            char* currentLightning = strtok(NULL, "\t");
            float LIGHTNING;
            sscanf(currentLightning, "%f", &LIGHTNING);


            char* currentPressure = strtok(NULL,"\t");
            double PRESSURE;
            sscanf(currentPressure, "%lf", &PRESSURE);



            char* currentTemp = strtok(NULL, "\t\n"); 

            double TEMP;
            sscanf(currentTemp, "%lf",&TEMP);


            if (TEMP < states[currentStates]->lo_temp_reading || states[currentStates]->lo_temp_timestamp == 0)
            {
                states[currentStates]->lo_temp_reading = TEMP;
                states[currentStates]->lo_temp_timestamp = TIMESTAMP;
            }
            if (TEMP > states[currentStates]->hi_temp_reading || states[currentStates]->hi_temp_timestamp == 0)
            {
                states[currentStates]->hi_temp_reading = TEMP;
                states[currentStates]->hi_temp_timestamp = TIMESTAMP;
            }

            currentStates++;
        }
        else
        {                                                
            (*(states +rankOfState))->num_records +=1;

            char* currentTimeStamp = strtok(NULL, "\t");
            unsigned long TIMESTAMP;
            sscanf(currentTimeStamp,"%lu", &TIMESTAMP);


            char* currentGeol = strtok(NULL, "\t");
            (*(states +rankOfState))->hi_millitime += *currentGeol;

            char* currentHumidity = strtok(NULL, "\t");
            double HUMIDITY;
            sscanf(currentHumidity, "%lf",&HUMIDITY);
            (*(states +rankOfState))->humidity += HUMIDITY;

            char* currentSnow = strtok(NULL, "\t");
            float SNOW;
            sscanf(currentSnow, "%f", &SNOW);
            (*(states +rankOfState))->snow += SNOW;

            char* currentCloud = strtok(NULL, "\t");
            double CLOUD;
            sscanf(currentCloud, "%lf",&CLOUD);
            (*(states +rankOfState))->cloud += CLOUD;

            char* currentLightning = strtok(NULL, "\t");
            float LIGHTNING;
            sscanf(currentLightning, "%f", &LIGHTNING);
            (*(states +rankOfState))->lightning += LIGHTNING;

            char* currentPressure = strtok(NULL,"\t");
            double PRESSURE;
            sscanf(currentPressure, "%lf", &PRESSURE);
            (*(states +rankOfState))->pressure += PRESSURE;

            char* currentTemp = strtok(NULL, "\t\n");
            double TEMP;
            sscanf(currentTemp, "%lf",&TEMP);

            (*(states +rankOfState))->temperature += TEMP;

            if (TEMP <= states[currentStates]->lo_temp_reading)
            {
                states[currentStates]->lo_temp_reading = TEMP;
                states[currentStates]->lo_temp_timestamp = *currentTimeStamp;
            }
            else if (*currentTemp > states[currentStates]->hi_temp_reading)
            {
                states[currentStates]->hi_temp_reading = *currentTemp;
                states[currentStates]->hi_temp_timestamp = *currentTimeStamp;
            }

            currentStates++;
        }
    }
}

如果我注释掉这些行,我的输出会打印出来,它只分析一行。

if (TEMP <= states[currentStates]->lo_temp_reading)
{
    states[currentStates]->lo_temp_reading = TEMP;
    states[currentStates]->lo_temp_timestamp = *currentTimeStamp;
}
else if (*currentTemp > states[currentStates]->hi_temp_reading)
{
   states[currentStates]->hi_temp_reading = *currentTemp;
   states[currentStates]->hi_temp_timestamp = *currentTimeStamp;
}

这是我使用的辅助函数:

int compareOrder(struct climate_info **states, char codex[3], int currentStates)          //returns the order of each state in the array
{
    int order = 0;
    while (order < currentStates)          //while order is less than number of states analyzed
    {
        if(strcmp((states[order])->code, codex) == 0)       //if the states is present
        {
            return order;
        }
        order++;                                                //increment here to check every line for when to update state codes
    }
    return -1;                                                  //returns -1 the state is not prsent in struct
}


int countStates(struct climate_info **states)                           //function to count number of states present
{
    int num = 0;
    while(num < 50 && states[num] != NULL)
    {
        num++;
    }
    return num;
}

【问题讨论】:

  • 如果你发MCVE的话会更容易回答。
  • 为什么要在 else 分支中增加 currentStates?您确实创建了任何新数据,这看起来不正确。
  • malloc(sizeof(struct climate_info) * num_states);: 如果num_states 不是 states 数组的长度,那么你如何检测后者的结束呢?或者你想创建一个n*n 数组?如果您的最终目标只是拥有一个指向单个结构的指针数组,那么您 malloc-ing 内存过多,malloc(sizeof(struct climate_info)) 就足够了。请注意,这不会导致失败,您只是在浪费内存。
  • 只是风格问题:避免全部大写的变量名,这些通常(按照惯例)用于常量(#define SOME_THING 1012),有时也用于枚举成员(但这些是常量,也是……)。
  • const int line_sz = 100; char line[line_sz]; 使用 C99 功能 VLA。仅供参考 - const int 不是常量,不像宏。

标签: c malloc token dynamic-memory-allocation


【解决方案1】:

您的代码存在很多问题,不幸的是,缺少很多信息,因此此答案基于假设。

编辑: 好的,这部分因您对问题的最新编辑而过时;仍然:建议的签名是优越的,因为它不依赖硬编码的最大数组长度,您还提供了“幻数”...

首先是countStates函数;我认为它看起来或多或少如下:

size_t countStates(struct climate_info** states)
{
    struct climate_info** end = states;
    while(*end)
        ++end;
    return end - states;
}

现在的问题是您可以轻松地迭代超出数组边界,从而导致未定义的行为并且可能已经在此函数中崩溃。修复,总数组大小/长度:

size_t countStates(struct climate_info** states, size_t length)
{
    struct climate_info** end = states;
    while(length-- && *end)
        ++end;
    return end - states;
}

然后让我们进入实际功能(不要怀疑更改格式/语法,如果没有另外表示,它是等效的 - 这些是我的个人喜好......):

// (size_t is more appropriate than int here...)
void analyze_file(FILE* file, struct climate_info* states[], size_t num_states)
{
    const size_t line_sz = 100;
    char line[line_sz];
    size_t currentStates = countStates(states, num_states);

    while (fgets(line, line_sz, file) != NULL) 
    {
        char* foundCode = strtok(line, "\t");                   
        int rankOfState = compareOrder(states, foundCode, currentStates);
        if(rankOfState == -1)             
        {
            // new states available at all?
            if(currentStates == num_states)
            {
                 // some appropriate error handling - need to decide you!
                 // for now, just returning from function:
                 return;
            }

            // just allocate one struct (assumption): 
            states[currentStates] = (struct climate_info *) malloc(sizeof(struct climate_info));

            // always check the result of malloc!
            if(!states[currentStates])
            {
                 // allocation failed, no memory available on OS!!!
                 // some appropriate error handling - need to decide you!
                 // for now, just returning from function:
                 return;
            }

            // prefer strncpy to assure you don't copy past the end!
            // sure, it will fill overdue bytes with 0, but still we are safer
            // (assumption: climate_info contains an array!)
            strncpy(states[currentStates]->code, foundCode, sizeof(states[currentStates]->code));
            states[currentStates]->num_records = 1;

            // ...

            // now you created a new struct with malloc; be aware
            // that memory is uninitialized and could contain *ANY*
            // data, reading uninitialized memory is undefined behaviour!
            //if (TEMP < states[currentStates]->lo_temp_reading || states[currentStates]->lo_temp_timestamp == 0)
            //{
                states[currentStates]->lo_temp_reading = TEMP;
            //    states[currentStates]->lo_temp_timestamp = TIMESTAMP;
            //}
            //if (TEMP > states[currentStates]->hi_temp_reading || states[currentStates]->hi_temp_timestamp == 0)
            //{
                states[currentStates]->hi_temp_reading = TEMP;
                states[currentStates]->hi_temp_timestamp = TIMESTAMP;
            //}
            // (it's a new set anyway, so just set the values...)

            currentStates++;
        }
        else
        {                                                
            ++states[rankOfState]->num_records; // just a little bit simpler...

            // ...

            states[rankOfState]->temperature += TEMP;

            if (TEMP <= states[currentStates]->lo_temp_reading)
            {
                states[currentStates]->lo_temp_reading = TEMP;
                states[currentStates]->lo_temp_timestamp = *currentTimeStamp;
            }
            // this should not have resulted in crash, but assign a bad value!
            else if (TEMP /* *currentTemp */ > states[currentStates]->hi_temp_reading)
            {
                states[currentStates]->hi_temp_reading = TEMP /* *currentTemp */;
                states[currentStates]->hi_temp_timestamp = *currentTimeStamp;
            }
            // same for timestamp in both branches: you don't want to assign first character of string,
            // but the parsed value (e. g. 1012, if string was "1012", *... would deliver 49
            // (ASCII code of character `1`; assuming you have ASCII compatible encoding)

            // wrong in this branch: you did NOT add a new element
            //currentStates++;
        }
    }
}

如前所述:这是基于我认为您正在尝试做的事情。如果我的假设是错误的,请发表评论...

【讨论】:

    猜你喜欢
    • 2012-10-10
    • 1970-01-01
    • 2017-06-25
    • 2017-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-29
    相关资源
    最近更新 更多