c - (char*)malloc(sizeof(char)) 导致段错误,怎么办?

标签 c segmentation-fault malloc

该代码在大多数输入上都可以正常工作,但是对于非常长的用户 ID,我会遇到段错误。我的问题是,malloc 如何导致段错误?简单地分配内存不应该导致这种情况。我通过使用 printf() 语句找到了问题区域,看来我的 read_line() 函数中的 malloc 就是问题所在,因为第二个“read_line”不打印,但 malloc 之前的第一个“read_line”打印。

谢谢。 - 克里斯

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define DELIM " " /* the delimiter */
#define MAX_CHANGE (10.0/86400.0)       /* 10kg/day */
/* seconds in a day is 24 hours * 60 minutes * 60 seconds */
#define MEM_OUT printf("%s","out of memory");

/* Defines Node structure. */
struct Node{
    char *id;
    float weight;
    int time;
    struct Node *next;
} *head, *p, *t, *last;

/* Constructor which returns a pointer to a new node. */
struct Node * new_node(int time, char *id, float w)
{   /*note malloc returns a pointer */
    struct Node *node = (struct Node *)malloc(sizeof(struct Node));
    node->time = time;
    node->id = (char *)malloc( (strlen(id) + 1) * sizeof(char));
    strcpy(node->id, id); //duplicate the id, so new node has own copy.
    node->weight = w;
    node->next = NULL;
return node;    
}

/* reads in line of characters until either a EOF or '\n' is encountered
    then places a the terminator '\0' at the end */
char * read_line(FILE *stream)
{
    printf("read_line");
char * temp = (char*)malloc(sizeof(char));
    printf("read_line");
char * line = (char*)malloc(sizeof(char));
    char c;
    *line = '\0';
    int i = 1; 
    //strchr()

    while( (c = getc(stream)) != EOF && c != '\n')
    {
        //if(c == EOF) return NULL;
        //realloc(line,++i);
        strcpy(temp,line);
        line = malloc(++i * sizeof(char));
        strcpy(line,temp);
        temp = malloc(i * sizeof(char));
        *(line + (i-1)) = '\0'; 
        *(line + (i-2)) = c; 
    }
free(temp);
if( i == 1) return NULL;
return line;
}

main() {

    int lasttime = 0, timestamp, duration, tokens;
    char * userID = NULL;
    char * lastuserID = NULL;
    char * line = NULL;
    float weight,lastweight,change,changePerTime;
    head = new_node(0,"",0.0);
    last = head;

    FILE *fp = fopen("C:\\Users\\chris\\Desktop\\School\\York\\cse\\2031 Software Tools\\Labs\\6\\input.txt","r");

    while( (line = read_line(fp)) != '\0') {
        printf("%s\n",line);
        //free(userID);
        line = strtok(line, " \n");
        if (line == NULL || sscanf(line,"%d",&timestamp) < 1 || timestamp == 0){
            printf("%s\n","Invalid time");
            continue;
            }
        line = strtok(NULL, " \n");
        if(line == NULL || isdigit(line[0]) || line[0] == '.') {
            printf("Illegal userID");
            //free(line);
            continue;
            }
        userID = (char * )malloc( (strlen(line)+1) * sizeof(char));
        strcpy(userID,line);
        strcat(userID," ");
        do{
            line = strtok(NULL," \n");      
        if(line != NULL && !isdigit(line[0]) && line[0] != '.'){    
            strcat(userID,line ); // adds ' ' and '\0'
            strcat(userID," "); 
            }
        }while(line != NULL && line[0] != '.' && !isdigit(line[0]) );
        userID[strlen(userID)-1] = '\0'; //erases the tailing space.
        if(strlen(userID) > 179){
            printf("Illegal userID\n");
            printf("mid"); 
            continue;
            printf("%s\n","after" );
            } 
        if(line != NULL)
            tokens = sscanf(line,"%f", &weight);
        if(line == NULL || tokens < 1 || weight < 30.0 || weight > 300.0)
            {printf("Illegal weight\n"); continue; }
        if (lasttime >= timestamp){
            printf("Nonmonotonic timestamps\n"); 
            continue;
            }
            lasttime = timestamp;

            // record is valid apst this point.
            /* t = last occurence of this userID, p = last userID*/
            for(p = head, t = NULL; p != NULL; p = p->next)
            {   
                if(strcmp(userID,p->id) == 0)
                    t=p;    
                last = p; // set last to last p.
            }
            if(t == NULL)
                printf("OK newuser\n");         
            else if(t != NULL)
            {
                duration = timestamp - t->time;
                change = weight - t->weight;
                changePerTime = change / duration;
                if(changePerTime < -MAX_CHANGE || changePerTime > MAX_CHANGE)
                    printf("Suspiciously large weight change\n");
                else
                    printf("OK\n");
            }
            /* add new node to end of list */
            last->next = new_node(timestamp,userID,weight);
            /* update lastnode */
            last = last->next;      
        free(line); 
        }
       fclose(fp);

/* count sum of id's for last valid user*/
    int count=0;
    for(p = head->next; p !=NULL; p=p->next)
    {
        if(strcmp(last->id,p->id) == 0)
            count++;
    }
//fclose(f);  // use if input from file is uncommented
// adds 1 to both demensions to hole axis
int tHeight = 11;
int tWidth = count + 1;
int qHeight = 10;
int qWidth= count;


/* builds the barchart */
    char bc[tHeight][tWidth];  // + 1 for y-axis

    /* draws axis and orgin */
    int a,b;
    for(a=0; a<tHeight; a++)
    {
        for(b=0;b<tWidth; b++)
        {
            if(a == qHeight && b == 0)
                bc[a][b] = '+';
            else if(a < tHeight && b == 0)
                bc[a][b] = '|';
            else if(a == qHeight && b > 0)
                bc[a][b] = '-';
        }
    }       

    /* prints the bars */
    int j=1, i, k, bh;
    for(p = head; p != NULL, j < tWidth; p=p->next)
    {               
        if(strcmp(last->id,p->id) == 0)
        {
            for(i = 9, k=0, bh = (int)(p->weight / 30);i >= 0; i--)
            {
                if(k < bh) 
                {
                    bc[i][j] = '*'; 
                    k++; // barheight
                }
                else 
                    bc[i][j] = ' ';
            }
        j++;
        }                                           
    }
/* prints the barchart */
    int m, n;
    for(m=0; m < tHeight; m++)
    {           
        for(n=0; n < tWidth; n++)
        {           
            printf("%c",bc[m][n]);
        }
        printf("%c",'\n');
    }
}

最佳答案

malloc 调用不会导致段错误。但您稍后可能会使用它们。

一些值得注意的事项

  • 您的 printf("read line") 语句在调用时不会立即打印出来,因为输出已被缓冲。如果您希望它们立即打印,请执行 printf("read line\n")。然后您将看到执行和使用您分配的微小缓冲区的代码都会导致崩溃。

  • while 循环中,您执行更多 malloc 调用并将返回值分配给变量,例如 templine,没有释放 templine 先前保存的内存指针,从而导致一些内存泄漏。您注释掉的 realloc 是更好的思考过程:line = realloc(line,++i * sizeof(*line));。对于 temp 也是如此。

<小时/> 内存分配问题

这里有一个非常有问题的区域:

    userID = (char * )malloc( (strlen(line)+1) * sizeof(char));
    strcpy(userID,line);
    strcat(userID," ");

userID 可以保存 line 中字符串的长度 (strlen(line)) 加上一个字节。但是空终止符还需要一个字节。您的 strcat(userID, "") 将写入超出为 userID 分配的缓冲区长度一个字节的内容。

关于c - (char*)malloc(sizeof(char)) 导致段错误,怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21959822/

相关文章:

c - 月供C方案

c - uint64 到 C 中的字符串

c - 使用 stdargs (va_start) 的 C 程序的奇怪行为 (SEGFAULT)

c++ - 为什么 C++ 在乘以大于 590x590 的矩阵时会出现段错误?

c - 动态分配的数组的大小是否存储在 RAM 中的某个位置?

c - 一般堆栈推送错误

c++ map 不返回 end() 即使它应该

c++ - 使用 GDB 修复大型项目中的双重释放或损坏 (!prev) 错误

c - 为什么使用宏 #define FREE_ARG char* 来分配由 malloc 分配的空闲内存(数值配方)

c - 给定递归程序的空间复杂度