You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从文件读字符串构建排序双向链表时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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 21:07:37