我正在从格式化的文件中读取并保存字符串,由于某种原因,我发现sscanf()
更改了testa_e->ident
的内容。
我放了一些printf
,发现问题发生在sscanf()
之后。我还通过打印检查了temp2
,temp5
和testa_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 secondword
和sscanf
,它应该向您显示testa_e->ident
的内容已更改,我想知道为什么以及如何解决此问题,因为我真的不知道...
答案 0 :(得分:4)
在函数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 );
为什么在函数中使用了指向头部的指针?
首先,如果要更改原始磁头,则需要通过引用传递它。其次在循环中
while ( *head != NULL ) head = &( *head )->next;
同样,指针指向最后一个节点的数据成员next
。因此,我们不会像在函数实现中那样更改局部变量curs
,而是最后一个节点的数据成员next
。因此,我们正在更改列表本身。
请注意将typedef定义为
typedef const char* identifier;
是一个坏习惯。
答案 1 :(得分:2)
主要问题是(除了他的答案中提到的@VladFromMoscow之外),在addent()
中,您仅将指针 id_ent
存储在结构中:
curs->ident=id_ent;
但这只是temp2
的地址,因此,如果您通过调用temp2
将其他内容复制到sscanf()
中,则会在testa_e->ident
中看到新值
将上面的线形更改为
curs->ident=strdup(id_ent);
创建副本。
而且,释放free(curs->ident)
curs