从文件读字符串构建排序双向链表时strcmp始终返回0的问题
双向链表strcmp始终返回0的问题解决
我实现了一个可在添加时按字母顺序排序字符串的双向链表,通过getopt从命令行获取输入文件。单独测试该双向链表时排序功能正常,但从文件读取字符串后,strcmp始终返回0。
原代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <getopt.h> #include <stdbool.h> #include <unistd.h> typedef struct Node{ char *word; struct Node *next; struct Node *prev; }Node; Node *head = NULL; Node *tail = NULL; Node* createNode(char *word){ Node *newNode = malloc(sizeof(Node)); newNode->word = word; newNode->next = NULL; newNode->prev = NULL; return newNode; } int compare(char *word, char *current){ return strcmp(word, current); } void insertNode(Node *newNode){ if(head == NULL){ head = newNode; tail = newNode; return; } Node *current = head; int comp; do{ comp = compare(newNode->word, current->word); printf("word: %s, current: %s, comp = %d\n",newNode->word, current->word, comp); //Only inserting node when word is less than current if(comp < 0){ if(current->prev == NULL){ head = newNode; current->prev = head; head->next = current; return; } newNode->next = current; newNode->prev = current->prev; current->prev->next = newNode; current->prev = newNode; printf("comp: %d, New node added for: %s\n\n", comp, newNode->word); return; } if(comp > 0 && current->next == NULL){ current->next = newNode; newNode->prev = current; tail = newNode; printf("New node: %s, added at the tail\n\n", newNode->word); return; } //printf("past first if\n"); if(comp > 0 && current->next){ printf("enter com > 0\n"); printf("current: %s\n", current->word); current = current->next; printf("current updated: %s\n\n", current->word); } //If both words are equal just drop newNode if(comp == 0){ //free(newNode); return; } } while(current != NULL); } void printList(int reverse){ if (reverse == 0){ Node *current = head; while (current != NULL) { printf("%s\n", current->word); current = current->next; } } else if(reverse == 1){ Node *current = tail; while (current != NULL) { printf("%s\n", current->word); current = current->prev; } } } void printListFile(FILE* fp, int reverse) { if (reverse == 0){ Node *current = head; while (current != NULL) { fprintf(fp, "%s\n", current->word); current = current->next; } } else if(reverse == 1){ Node *current = tail; while (current != NULL) { fprintf(fp, "%s\n", current->word); current = current->prev; } } } void freeList() { while (head != NULL) { Node* next = head->next; free(head->word); free(head); head = next; } } int main(int argc, char **argv) { extern char *optarg; extern int optind; int dflag = 0, oflag = 0; char* inputFile = NULL; char* outputFile = NULL; int c, err = 0; //Usage static char usage[] = "usage: %s doublesort [-d] [-o output_file_name] input_file_name\n"; //Getopt while ((c = getopt(argc, argv, "do")) != -1) switch (c) { case 'd': dflag = 1; break; case 'o': oflag = 1; outputFile = optarg; break; case '?': err = 1; break; } if (err) { fprintf(stderr, usage, argv[0]); exit(1); } if (optind >= argc) { printf("optind = %d, argc = %d\n", optind, argc); fprintf(stderr, "%s: missing input file name\n", argv[0]); fprintf(stderr, usage, argv[0]); return 1; } if (optind < argc) { inputFile = argv[optind]; } FILE* fin = stdin; FILE* fout = stdout; if (inputFile != NULL) { fin = fopen(inputFile, "r"); if (fin == NULL) { fprintf(stderr, "Error: cannot open file %s for reading.\n", inputFile); return 1; } } if(oflag == 1){ if (outputFile != NULL) { fout = fopen(outputFile, "w"); if (fout == NULL) { fprintf(stderr, "Error: cannot open file %s for writing.\n", outputFile); if (fin != stdin) { fclose(fin); } return 1; } } } //Inserting node into doubly link list char buf[100]; while (fgets(buf, sizeof(buf), fin) != NULL) { int len = strlen(buf); if (len > 0 && buf[len - 1] == '\n') { buf[len - 1] = '\0'; } insertNode(createNode(buf)); } if(oflag == 1){ printListFile(fout, dflag); } else{ printList(dflag); } // free memory and close files freeList(); if (fin != stdin) { fclose(fin); } if (fout != stdout) { fclose(fout); } return 0; }
错误原因
核心问题是所有节点的word指针都指向了栈上的同一个buf数组:
- 在
main函数中,buf是局部栈数组,每次调用fgets都会覆盖它的内容。 createNode函数只是把buf的地址直接赋值给newNode->word,没有复制字符串的实际内容。- 这导致链表中所有节点的
word指向同一块内存区域,strcmp比较的是相同地址的内容,因此始终返回0。
解决方法
修改createNode函数,为每个字符串分配独立的堆内存,复制输入的字符串内容:
- 可以用
strdup函数(自动分配内存并复制字符串),或者手动用malloc+strcpy实现。
修改后的createNode函数(使用strdup):
Node* createNode(char *word){ Node *newNode = malloc(sizeof(Node)); if (newNode == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } // 用strdup复制字符串,自动分配内存 newNode->word = strdup(word); if (newNode->word == NULL) { perror("strdup failed"); free(newNode); exit(EXIT_FAILURE); } newNode->next = NULL; newNode->prev = NULL; return newNode; }
如果系统不支持strdup,可以手动实现:
Node* createNode(char *word){ Node *newNode = malloc(sizeof(Node)); if (newNode == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } // 手动分配内存并复制字符串 size_t len = strlen(word) + 1; newNode->word = malloc(len); if (newNode->word == NULL) { perror("malloc for word failed"); free(newNode); exit(EXIT_FAILURE); } strcpy(newNode->word, word); newNode->next = NULL; newNode->prev = NULL; return newNode; }
额外优化
原代码中当strcmp返回0时,没有释放newNode会导致内存泄漏,建议在该分支添加释放逻辑:
if(comp == 0){ free(newNode->word); free(newNode); return; }
内容的提问来源于stack exchange,提问作者Luis V
相关产品推荐
相关产品推荐

