我尝试printf时出现分段错误

时间:2016-01-10 20:12:50

标签: c struct

为什么我在尝试打印列表中的第二个成员时会得到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;
}

3 个答案:

答案 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中创建Adresseadd的副本,因为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,以及检查和处理太长而不适合你预定义长度的字符串。

希望这有帮助