在C中添加一条指令后的奇怪程序行为

在C中添加一条指令后的奇怪程序行为,c,gdb,C,Gdb,实际上,我用同样的代码问了另一个问题,但这是非常不同的。 下面的代码显示了一个非常恼人的行为。我在代码中加入了尽可能多的注释,这样您就可以了解发生了什么 #include <stdio.h> #include <stdlib.h> /* This is a struct describing properties of an element */ struct element{ int age; char* name; }; /* This struc

实际上,我用同样的代码问了另一个问题,但这是非常不同的。 下面的代码显示了一个非常恼人的行为。我在代码中加入了尽可能多的注释,这样您就可以了解发生了什么

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

/* This is a struct describing properties of an element */
struct element{
    int age;
    char* name;
};

/* This struct contains a pointer to a pointer on a element "struct element" */
struct person{
    struct element** p;
    size_t size;
    unsigned int id;
};

/* This function initializes a struct person by allocating memory for it */
struct person* init(int _size)
{
    if(_size == 0)
    {
         printf("You gonna have to make some choices \n");
         exit(1);
    }
    struct person* sample = (struct person* )malloc(_size*sizeof(struct person));
    sample->p = (struct element** ) malloc(_size*sizeof(struct element*));
    sample->id = 0;
    sample->size = _size;
    return sample;
}

/* use this function to insert a new element in the struct */
void insert(struct person* sample, char* _name, int _age)
{
    if (sample->id >= sample->size) {
        sample->p = (struct element** ) realloc(sample->p, (sample->size*2) * sizeof(struct element*));
        if(sample->p == NULL){
            printf("Get a new RAM buddy \n");
            exit(1);
        }
    }
    sample->p[sample->id]->name = _name; 
    sample->p[sample->id]->age = _age;  /* of course, this will cause trouble too because it has the same construct as the previous one */
    sample->id++;
}


/* main entry */
int main(int argc, char** argv)
{
    int i = 0;
    struct person* student = init(10); /* Allocating space for 10 students */
    insert(student, "baby", 2);
    insert(student, "dady", 33);
    /* if you remove this line, the program runs, but GDB will signal a segmentation fault. If you keep it, the program will freeze and GDB will behave as expected */
    /* I don't understand why this is happening!!!??? */
    insert(student, "grandma", 63);
    printf("Your name is %s and your age is %d \n", student->p[1]->name, student->p[1]->age);  
    /* When you only insert two elements, use the results here to match with GDB's results*/
    printf("student->p: %p \n", &student->p);
    printf("student->p[0]: %p \n", &student->p[0]);
    printf("student->p[1]: %p \n", &student->p[1]);
    printf("student->p[0]->age: %p \n", &student->p[0]->age);
    printf("student->p[0]->name: %p \n", &student->p[0]->name);
    /* Won't work for more than two elements inserted */    
    for(i = 0; i < 2; i++){
        printf("Your name is %s and your age is %d \n", student->p[i]->name, student->p[i]->age);
    }

    return 0;
}
正如您在代码注释中所看到的,程序在工作时提供的数据与使用GDB获得的数据不匹配


谢谢您的帮助。

据我所知,您尚未为元素分配任何内存。 这里为指向元素的指针分配内存:

sample->p = (struct element** ) malloc(_size*sizeof(struct element*));

据我所知,您尚未为元素分配任何内存。 这里为指向元素的指针分配内存:

sample->p = (struct element** ) malloc(_size*sizeof(struct element*));

如果调试器的存在改变了程序的行为方式,则很可能是滥用内存或线程。与此类似,您没有分配元素本身。

如果调试器的存在改变了程序的行为方式,则很可能是滥用内存或线程。与此类似,您没有分配元素本身。

问题的根本原因是您正在分配指向
struct element
的指针,但这些指针未初始化-您没有分配任何实际的
struct element
对象。当您取消引用这些无效指针时,您将获得未定义的行为

也不需要分配
结构体person
结构体的
大小
——您只需要使用一个。您的
struct person
应该是这样的(注意
p
的类型不同):

然后,您的
init()
函数应该如下所示:

struct person* init(int _size)
{
    if(_size < 1)
    {
         printf("You gonna have to make some choices \n");
         exit(1);
    }
    struct person* sample = malloc(sizeof *sample);
    sample->p = malloc(_size * sizeof sample->p[0]);
    sample->id = 0;
    sample->size = _size;
    return sample;
}
void insert(struct person* sample, char* _name, int _age)
{
    if (sample->id >= sample->size) {
        sample->size *= 2;
        sample->p = realloc(sample->p, sample->size * sizeof sample->p[0]);
        if(sample->p == NULL){
            printf("Get a new RAM buddy \n");
            exit(1);
        }
    }
    sample->p[sample->id].name = _name; 
    sample->p[sample->id].age = _age;  /* of course, this will cause trouble too because it has the same construct as the previous one */
    sample->id++;
}

然后,主函数应该使用
student->p[i].name
student->p[i].age
来访问数据。

问题的根本原因是您正在将指针分配给
struct element
,但这些指针未初始化-您没有分配任何实际的
struct element
对象。当您取消引用这些无效指针时,您将获得未定义的行为

也不需要分配
结构体person
结构体的
大小
——您只需要使用一个。您的
struct person
应该是这样的(注意
p
的类型不同):

然后,您的
init()
函数应该如下所示:

struct person* init(int _size)
{
    if(_size < 1)
    {
         printf("You gonna have to make some choices \n");
         exit(1);
    }
    struct person* sample = malloc(sizeof *sample);
    sample->p = malloc(_size * sizeof sample->p[0]);
    sample->id = 0;
    sample->size = _size;
    return sample;
}
void insert(struct person* sample, char* _name, int _age)
{
    if (sample->id >= sample->size) {
        sample->size *= 2;
        sample->p = realloc(sample->p, sample->size * sizeof sample->p[0]);
        if(sample->p == NULL){
            printf("Get a new RAM buddy \n");
            exit(1);
        }
    }
    sample->p[sample->id].name = _name; 
    sample->p[sample->id].age = _age;  /* of course, this will cause trouble too because it has the same construct as the previous one */
    sample->id++;
}

然后,主函数应该使用
student->p[i].name
student->p[i].age
来访问数据。

这里使用的是p[],没有首先初始化它来指向任何东西。您只为指针分配了空间,但尚未初始化它们以指向任何对象。所以当你这么做的时候

sample->p[sample->id]->name = _name; 
sample->p[sample->id]->age = _age;
p指向内存中的某个地方,您正在修改它指向的内容

而是插入一个

sample->p[sample->id] = malloc(struct element);
sample->p[sample->id]->name = _name; 
sample->p[sample->id]->age = _age;
它应该会起作用


注:通常你不会在C中使用malloc,这里你使用的是p[],没有先初始化它来指向任何东西。您只为指针分配了空间,但尚未初始化它们以指向任何对象。所以当你这么做的时候

sample->p[sample->id]->name = _name; 
sample->p[sample->id]->age = _age;
p指向内存中的某个地方,您正在修改它指向的内容

而是插入一个

sample->p[sample->id] = malloc(struct element);
sample->p[sample->id]->name = _name; 
sample->p[sample->id]->age = _age;
它应该会起作用


注:通常你不会在C中施放malloc,这是最有用的!!事实上,我从你的回答中学到了很多!谢谢!但我有一个问题要问你:我使用双指针(struct元素**)通过下标访问元素。你怎么解释你只用一个指针就能做到这一点?另外,我不是C大师,所以这可能是一个初学者的问题。Thanks@Khan2011:指向类型
T
的指针可以指向类型
T
的单个对象,也可以指向类型
T
的连续对象数组中的第一个对象。应用于此类指针的下标运算符
[i]
访问数组中的第(i+1)个对象。感谢您的解释。所以通常的数组的东西!!!很像char*name,它相当于char name[0]。现在比以前更清楚了。这是最有用的!!事实上,我从你的回答中学到了很多!谢谢!但我有一个问题要问你:我使用双指针(struct元素**)通过下标访问元素。你怎么解释你只用一个指针就能做到这一点?另外,我不是C大师,所以这可能是一个初学者的问题。Thanks@Khan2011:指向类型
T
的指针可以指向类型
T
的单个对象,也可以指向类型
T
的连续对象数组中的第一个对象。应用于此类指针的下标运算符
[i]
访问数组中的第(i+1)个对象。感谢您的解释。所以通常的数组的东西!!!很像char*name,它相当于char name[0]。现在比以前更清楚了。我也试过你的方法!!哦,天哪!太聪明了!谢谢,我也试过你的方法!!哦,天哪!太聪明了!谢谢