为什么我在尝试打印列表中的第二个成员时会得到segmentationfault
?
打印列表的第一个元素后,调试器打开stdio.h并说:
在C:\ TDM-GCC-32 \ include \ stdio.h:255
在C:\ TDM-GCC-32 \ include \ stdio.h:256
在C:\ TDM-GCC-32 \ include \ stdio.h:258
在C:\ TDM-GCC-32 \ include \ stdio.h:259
这是代码。
#include <stdio.h>
#include <stdlib.h>
struct Student {
char *Name;
char *Adresse;
unsigned long Mtnr;
short Kurse;
struct Student *next;
struct Student *previous;
};
typedef struct Student Student;
Student *liste = NULL, *ende = NULL;
void add(char Name, char Adresse, unsigned long Mtnr, short Kurse) {
Student *add;
ende->next = malloc(sizeof(Student));
add = ende->next;
add->Name = Name;
add->Adresse = Adresse;
add->Mtnr = Mtnr;
add->Kurse = Kurse;
add->previous = ende;
add->next = NULL;
ende = ende->next;
}
void Ausgabe(Student *Anfang) {
while (Anfang != NULL) {
printf("%s %s %d %d \n", Anfang->Name, Anfang->Adresse, Anfang->Mtnr, Anfang->Kurse);
Anfang = Anfang->next;
}
}
int main() {
liste = malloc(sizeof(Student));
ende = liste;
liste->Name = "Anna Musterfrau";
liste->Adresse = "Am Schwarzberg-Campus 3";
liste->Mtnr = 22222;
liste->Kurse = 2;
liste->next = NULL;
liste->previous = NULL;
add("Hans Peter", "Kasernenstrasse 4", 4444, 4);
Ausgabe(liste);
return 0;
}
答案 0 :(得分:4)
错误发生在add()
函数的声明中。字符串应该是char指针,而不是字符。
void add(char *Name, char *Adresse, unsigned long Mtnr, short Kurse){
答案 1 :(得分:1)
函数add
的签名与Student
成员的声明和用法不一致。如下更改签名。
void add(char* Name, char* Adresse, unsigned long Mtnr, short Kurse)
从长远来看,可能还需要在Name
中创建Adresse
和add
的副本,因为add
的调用方可能会释放它们,可能会导致不受欢迎的行为。
答案 2 :(得分:0)
虽然Marc对他的观察是正确的,但还有一件事你可以在这里解决。
当你添加一条记录时,你会分配它,但是你没有分配它的指针内容(特别是=用于名称和地址指针)。 add函数只是将它们指向输入的地址。这是一个问题,因为提供给add函数的地址中的数据很可能会改变,例如,如果它是用户输入或其他一些外部缓冲区。
在下面的代码中我修复了'name',但保留了地址。请运行它,看看会发生什么。 (阿萨夫的记录显示大卫的地址)
希望这会有所帮助
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
char *Name;
char *Adresse;
unsigned long Mtnr;
short Kurse;
struct Student *next;
struct Student *previous;
};
typedef struct Student Student;
Student *liste = NULL, *ende = NULL;
void add(char *Name, char *Adresse, unsigned long Mtnr, short Kurse) {
Student *add;
ende->next = malloc(sizeof(Student));
add = ende->next;
add->Name = malloc(strlen(Name)+1);
strcpy(add->Name, Name);
add->Adresse = Adresse;
add->Mtnr = Mtnr;
add->Kurse = Kurse;
add->previous = ende;
add->next = NULL;
ende = ende->next;
}
void Ausgabe(Student *Anfang) {
while (Anfang != NULL) {
printf("%s %s %d %d \n", Anfang->Name, Anfang->Adresse, Anfang->Mtnr, Anfang->Kurse);
Anfang = Anfang->next;
}
}
int main() {
char name_buf[100];
char address_buf[100];
liste = malloc(sizeof(Student));
ende = liste;
liste->Name = "Anna Musterfrau";
liste->Adresse = "Am Schwarzberg-Campus 3";
liste->Mtnr = 22222;
liste->Kurse = 2;
liste->next = NULL;
liste->previous = NULL;
add("Hans Peter", "Kasernenstrasse 4", 4444, 4);
sprintf(name_buf,"assaf stoler");
sprintf(address_buf,"maria 8");
add(name_buf, address_buf, 8888, 8);
sprintf(name_buf,"david david");
sprintf(address_buf,"some street 9");
add(name_buf, address_buf, 9999, 9);
Ausgabe(liste);
return 0;
}
编辑:Op问了一些问题,评论空间有限,所以我将在下面添加:
指针只是指向内存中某个对象的对象。它的大小是固定的。它指向的内容会有所不同。
当您在结构中包含指向字符串的指针时,需要分配/计算保留字符串的空间。它不是sizeof(struct)的一部分。
在您的原始示例中,指针指向常量字符串(驻留在静态代码中,通常是数据部分,由编译器分配),这就是原始代码能够访问字符串的原因。
在更现实的情况下,输入数据不是程序数据的一部分,而是通过某种输入方法(我的* buf要模拟)接收。因此,将您的姓名和地址指向它会破坏程序,因为您指向的指针可能会更改其内容。因此需要复制数据(字符串/数组),因为我们复制数据,我们需要为它分配空间,并指向我们的(名称/地址)指针。
备用选项是对名称和地址使用非指针数组,如:
struct Student {
char Name[20];
char Adresse[60];
unsigned long Mtnr;
...
}
在这种情况下,sizeof(struct Student)实际上会包含这些字段的所有空间。你仍然需要使用strcpy或memcpy,以及检查和处理太长而不适合你预定义长度的字符串。
希望这有帮助