C中的strcmp()分段错误

8ehkhllq  于 2023-03-28  发布在  其他
关注(0)|答案(1)|浏览(154)

当我调用这个函数时,我的代码总是在strcmp中中断,并返回一个Segmentation Error,没有提供更多的信息。

stop_t *getStop(char *name) {
    node_t *current = stop_list_head;
    stop_t *stop;

    while (current != NULL) {
        stop = current->stop;
        if (stop != NULL) {
            if (stop->name != NULL) {
                if (strcmp(stop->name, name) == 0) {
                    return stop;
                }
            }
        }
        current = current->next;
    }
    return NULL;
}

当我插入一个printf("%s", stop->name);时,它返回了相同的分段错误,但在printf上。
我该怎么补救呢?
最小重现性示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LENGTH_STOP 50

typedef struct {
    int routeCounter;
    double latitude;
    double longitude;
    char name[MAX_LENGTH_STOP + 1];
} stop_t;

typedef struct node {
    stop_t *stop;
    struct node *next;
} node_t;

void printStopList();

node_t *stop_list_head = NULL;

int main() {
    stop_t *stopPtr = NULL;
    stop_t stop;
    char name[MAX_LENGTH_STOP + 1];

    /* Input Example: Praca de Espanha ; */
    fgets(name, BUFSIZ, stdin);

    stopPtr = getStop(name);
    /* Create new stop if it doesn't exist already, else print error.*/
    if (stopPtr == NULL) {
        generateStop(name);
    } else {
        printf("<Error 01>: Stop already exists.\n");
    }
}

/* Determines if the stop already exists based on the name */
stop_t *getStop(char *name) {
    node_t *current = stop_list_head;
    stop_t *stop;

    while (current != NULL) {
        stop = current->stop;
        if (stop != NULL) {
            if (stop->name != NULL) {
                if (strcmp(stop->name, name) == 0) {
                    return stop;
                }
            }
        }
        current = current->next;
    }
    return NULL;
}

/* Generates a stop instance and adds it to the global linked list*/
void generateStop(char name[]) {
    stop_t *stop = NULL;

    stop = (stop_t *)malloc(sizeof(stop_t));

    strcpy(stop->name, name);
    stop->routeCounter = 0;
    addStopToList(stop);
    free(stop);
}

/* Adds created stops to a global linked list (stop_list_head)*/
void addStopToList(stop_t *stop) {

    node_t *new_node = (node_t *)malloc(sizeof(node_t));
    node_t *current;

    new_node->stop = stop;
    new_node->next = NULL;

    if (stop_list_head == NULL) {
        stop_list_head = new_node;
    } else {
        current = stop_list_head;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = new_node;
    }

    free(new_node);
}
4ktjp1zp

4ktjp1zp1#

存在多个问题:

  • 你释放函数中新分配的结构。这会导致在以后读取它们时出现未定义的行为,例如:当strcmp访问stop->name
  • 读取name时,fgets传递了一个无效的大小BUFSIZ,该大小远大于MAX_LENGTH_STOP + 1。这可能会导致缓冲区溢出
  • 你没有测试fgets()的返回值,如果从空文件重定向,会导致无效行为。
  • fgets()name数组的末尾留下尾随的换行符:它将被存储到停止列表中。
  • 如果name参数比stop_t结构中的name字段长,则strcpy(stop->name, name);可能会导致缓冲区溢出。
  • 最小的示例实际上不会导致分段错误,因为停止列表为空。

以下是修改后的版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LENGTH_STOP 50

typedef struct stop {
    int routeCounter;
    double latitude;
    double longitude;
    char name[MAX_LENGTH_STOP + 1];
} stop_t;

typedef struct node {
    stop_t *stop;
    struct node *next;
} node_t;

node_t *stop_list_head;

/* Determines if the stop already exists based on the name */
stop_t *getStop(const char *name) {
    node_t *current = stop_list_head;

    while (current != NULL) {
        stop_t *stop = current->stop;
        if (stop != NULL && strcmp(stop->name, name) == 0) {
            return stop;
        }
        current = current->next;
    }
    return NULL;
}

/* Adds created stops to a global linked list (stop_list_head)*/
void addStopToList(stop_t *stop) {
    node_t *new_node = (node_t *)malloc(sizeof(node_t));
    if (new_node == NULL) {
        perror("cannot allocate node_t");
        exit(1);
    }

    new_node->stop = stop;
    new_node->next = NULL;

    if (stop_list_head == NULL) {
        stop_list_head = new_node;
    } else {
        node_t *current = stop_list_head;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = new_node;
    }
}

/* Generates a stop instance and adds it to the global linked list*/
void generateStop(const char *name) {
    stop_t *stop = (stop_t *)calloc(sizeof(stop_t), 1);
    if (stop == NULL) {
        perror("cannot allocate stop_t");
        exit(1);
    }
    strncat(stop->name, name, sizeof(stop->name) - 1);
    addStopToList(stop);
}

int main(void) {
    for (;;) {
        char name[MAX_LENGTH_STOP + 2];

        /* Input Example: Praça de Espanha ; */
        if (!fgets(name, sizeof name, stdin))
            return 1;
        /* strip the trailing newline if present */
        name[strcspn(name, "\n")] = '\0';
        /* stop on an empty line */
        if (*name == '\0')
            break;
        /* Create new stop if it doesn't exist already, else print error.*/
        if (getStop(name)) {
            printf("<Error 01>: Stop already exists: %s\n", name);
        } else {
            generateStop(name);
        }
    }
    return 0;
}

相关问题