странное поведение программы после добавления одной инструкции в C - PullRequest
0 голосов
/ 24 марта 2011

На самом деле, я задал еще один вопрос с тем же кодом, но это сильно отличается. У меня есть этот код ниже, который отображает очень раздражающее поведение. Я включил в код как можно больше комментариев, чтобы вы могли понять, что происходит.

#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) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: C:\Users\NTWALI\Desktop\tests\help\bin\Debug/help.exe
[New thread 11408.0x1228]
Error: dll starting at 0x770a0000 not found.
Error: dll starting at 0x76ab0000 not found.
Error: dll starting at 0x770a0000 not found.
Error: dll starting at 0x76d40000 not found.

Program received signal SIGSEGV, Segmentation fault.
0x0040146f in insert (sample=0x6816c0, _name=0x409031 "ntwali", _age=22) at C:\Users\NTWALI\Desktop\tests\help\main.c:44
44          sample->p[sample->id]->name = _name; 
(gdb) p sample
$4 = (struct person *) 0x6816c0
(gdb) p sample->p
$5 = (struct element **) 0x681750
(gdb) p sample->p[0]
$6 = (struct element *) 0xbaadf00d
(gdb) p sample->p[1]
$7 = (struct element *) 0xbaadf00d
(gdb)

Как видно из комментариев к коду, данные, которые программа выдает, когда она работает, не совпадают с данными, полученными с помощью GDB.

Спасибо за помощь.

Ответы [ 4 ]

3 голосов
/ 24 марта 2011

Если наличие отладчика изменяет поведение вашей программы, вы, скорее всего, неправильно используете память или потоки. Точно так же, как daven11 указывает на , вы не выделяете сами элементы.

3 голосов
/ 24 марта 2011

Насколько я вижу, вы не выделили никакой памяти для элемента.Здесь вы выделяете память для указателя на элемент:

sample->p = (struct element** ) malloc(_size*sizeof(struct element*));
0 голосов
/ 24 марта 2011

здесь вы используете 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;

, и это должноработа

PS.обычно вы не разыгрываете malloc в C

0 голосов
/ 24 марта 2011

Основной причиной вашей проблемы является то, что вы выделяете указатели для struct element, но эти указатели не инициализированы - вы не выделяете никаких реальных struct element объектов. Когда вы разыменовываете эти недействительные указатели, вы получаете неопределенное поведение.

Нет также необходимости выделять _size из struct person структур - вы всегда используете только одну. Ваш struct person должен выглядеть следующим образом (тип примечания p отличается):

struct person{
    struct element *p;
    size_t size;
    unsigned int id;
};

и ваша 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;
}

Функция insert() должна выглядеть следующим образом:

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 для доступа к данным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...