C语言中调用strcmp()触发Segmentation Fault问题排查与修复
问题与修复方案
问题描述
调用getStop函数时,代码总是在strcmp处崩溃并返回Segmentation Error,插入printf("%s", stop->name);后,崩溃点转移到printf处。以下是最小可复现代码:
原getStop函数代码
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; }
完整最小可复现代码
#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); }
核心错误分析
崩溃的根源是两处非法的内存释放:
generateStop中释放了stop指针:用malloc创建stop实例后,将其加入链表立刻调用free(stop),导致链表中存储的stop指针变成野指针,后续访问stop->name时会触发段错误。addStopToList中释放了new_node:new_node是链表的节点,刚加入链表就free(new_node),导致链表节点本身被释放,遍历链表时会访问非法内存。
另外还有一个次要问题:fgets会读取输入末尾的换行符\n,导致存储的名字带换行符,后续调用getStop时会因字符串不匹配重复创建节点,需要额外处理去掉换行符。
修复后的代码
修改generateStop函数
移除free(stop);,保留malloc出来的stop实例,并处理换行符:
void generateStop(char name[]) { stop_t *stop = NULL; stop = (stop_t *)malloc(sizeof(stop_t)); // 去掉fgets读取的换行符 name[strcspn(name, "\n")] = '\0'; strcpy(stop->name, name); stop->routeCounter = 0; addStopToList(stop); }
修改addStopToList函数
移除free(new_node);,保留链表节点:
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; } }
完整修复后的代码
#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; node_t *stop_list_head = NULL; int main() { stop_t *stopPtr = NULL; char name[MAX_LENGTH_STOP + 1]; /* Input Example: Praca de Espanha */ fgets(name, sizeof(name), stdin); // 限制读取长度避免缓冲区溢出 stopPtr = getStop(name); if (stopPtr == NULL) { generateStop(name); } else { printf("<Error 01>: Stop already exists.\n"); } } stop_t *getStop(char *name) { node_t *current = stop_list_head; stop_t *stop; char stripped_name[MAX_LENGTH_STOP + 1]; strcpy(stripped_name, name); // 统一去掉换行符,保证匹配一致性 stripped_name[strcspn(stripped_name, "\n")] = '\0'; while (current != NULL) { stop = current->stop; if (stop != NULL && strcmp(stop->name, stripped_name) == 0) { return stop; } current = current->next; } return NULL; } void generateStop(char name[]) { stop_t *stop = (stop_t *)malloc(sizeof(stop_t)); name[strcspn(name, "\n")] = '\0'; strcpy(stop->name, name); stop->routeCounter = 0; addStopToList(stop); } 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; } }
内容的提问来源于stack exchange,提问作者mcsmachado
相关产品推荐
相关产品推荐

