我正在从格式化的文件中读取和保存字符串,由于某种原因,我发现sscanf()更改了testa_e->ident内容。

我已经放了一些printf,我发现问题在sscanf()之后立即发生。我也通过打印检查了temp2temp5testa_e的地址,但是它们是不同的。

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

#define string 30
#define line 100

typedef const char *identifier;

struct nodo_id {
    identifier ident;
    struct nodo_id *next;
};
typedef struct nodo_id nodo_id;

nodo_id *testa_e = NULL;

void addent(const char *id_ent) {
    if (testa_e == NULL) {
        testa_e = malloc(sizeof(nodo_id));
        testa_e->ident = id_ent;
        testa_e->next = NULL;
    } else {
        nodo_id *curs = testa_e;
        while (curs != NULL) {
            curs = curs->next;
        }
        curs = malloc(sizeof(nodo_id));
        curs->ident = id_ent;
        curs->next = NULL;
    }
}

int main() {
    char temp[line];
    char temp2[string];
    char temp5[string];

    fgets(temp, line, stdin);
    while (strncmp(temp, "end", 3) != 0) {
        if (strncmp(temp, "addent", 6) == 0) {
            if (testa_e != NULL)
                printf("\nbefore sscanf: %s\n", testa_e->ident);
            sscanf(temp, "%s %s", temp5, temp2);
            if (testa_e != NULL)
                printf("\nafter sscanf: %s\n", testa_e->ident);
            addent(temp2);
        }
        fgets(temp, line, stdin);
    }
}


这里的代码重现了完全相同的问题。启动后,在终端上并在addent firstword附近写addent secondwordsscanf,它应该显示testa_e->ident内容已更改,我想知道为什么以及如何解决此问题,因为我真的不知道。 ..

最佳答案

在功能addent中,此循环

        while(curs!=NULL){
            curs=curs->next;
        }


迭代直到curs等于NULL

然后您要更改指针

    curs=malloc(sizeof(nodo_id));
    curs->ident=id_ent;
    curs->next=NULL;


列表本身未更改。您仅更改了局部变量curs

通过以下方式更改循环

        while ( curs->next != NULL ){
            curs = curs->next;
        }


然后

    curs->next = malloc( sizeof( nodo_id ) );
    curs->next->ident = id_ent;
    curs->next->next = NULL;


另一个问题是您正在使用指向本地数组的指针

char temp2[string];
//...
addent(temp2);


因此,将存储在数组中的最后一个节点将由所有节点指向。您需要为将存储在列表中的每个字符串动态分配内存,并将地址分配给数据成员ident。在这种情况下,您必须从其声明中删除限定符const

考虑到使函数依赖于全局变量是一个坏主意,

函数addent的更好定义可以如下所示

struct nodo_id{
    char *ident;
    struct nodo_id* next;
};
typedef struct nodo_id nodo_id;

int addent( nodo_id **head, const char *id_ent )
{
    nodo_id *new_nodo_id = malloc( sizeof( nodo_id ) );
    int success = new_nodo_id != NULL;

    if ( success )
    {
        new_nodo_id->ident = malloc( strlen( id_ent ) + sizeof( ( char )'\0' ) );

        success = new_nodo_id->ident != NULL;

        if ( ! success )
        {
            free( new_nodo_id );
        }
        else
        {
            strcpy( new_nodo_id->ident, id_ent );
            new_nodo_id->next = NULL;

            while ( *head != NULL ) head = &( *head )->next;

            *head = new_nodo_id;
        }
    }

    return success;
}


函数可以像

addent( &testa_e, temo2 );


为什么在函数中使用了指向head的指针?

首先,如果要更改原始磁头,则需要通过引用传递它。其次在循环中

while ( *head != NULL ) head = &( *head )->next;


指针再次指向最后一个节点的数据成员next。因此,我们不像在函数实现中那样更改局部变量curs,而是最后一个节点的数据成员next。因此,我们正在更改列表本身。

注意将这样的typedef定义为

typedef const char* identifier;


是一个坏习惯。

关于c - 为什么此sscanf会修改一些我不想修改的数据?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57433549/

10-15 17:56