Вопрос:

C Указатель и распределение памяти: массивы Realloc и прохождение указателя

c pointers memory-management reference

1243 просмотра

5 ответа

1274 Репутация автора

Для тех, кто имеет опыт работы с C, это будет простая проблема выделения / обращения к памяти:

Вот мои структуры данных:

struct configsection {
    char *name;
    unsigned int numopts;
    configoption *options;
};
typedef struct configsection configsection;

struct configfile {
    unsigned int numsections;
    configsection *sections;
};
typedef struct configfile configfile;

Вот мои процедуры для инициализации раздела конфигурации или файла конфигурации и для добавления раздела конфигурации в файл конфигурации:

// Initialize a configfile structure (0 sections)
void init_file(configfile *cf) {
    cf = malloc(sizeof(configfile));
    cf->numsections = 0;
}
// Initialize a configsection structure with a name (and 0 options)
void init_sec(configsection *sec, char *name) {
    sec = malloc(sizeof(configsection));
    sec->numopts = 0;
    sec->name = name;
    printf("%s\n", sec->name);
}
// Add a section to a configfile
void add_sec(configfile *cf, configsection *sec) {
    // Increase the size indicator by 1
    cf->numsections = cf->numsections + 1;
    // Reallocate the array to accommodate one more item
    cf->sections = realloc(cf->sections, sizeof(configsection)*cf->numsections);
    // Insert the new item
    cf->sections[cf->numsections] = *sec;
}

Я считаю, что моя проблема возникает в моей функции init_sec (). Вот пример:

int main(void) {

// Initialize test configfile
configfile *cf;
init_file(cf);

// Initialize test configsections
configsection *testcs1;
init_sec(testcs1, "Test Section 1");
// Try printing the value that should have just been stored
printf("test name = %s\n", testcs1->name);

Несмотря на то, что printf()in init_sec()успешно печатает имя, которое я только что сохранил в разделе конфигурации, попытка того же самого в printf()of main()вызывает ошибку сегментации. Далее addsec()выдает ошибку сегментации.

Автор: Xander Dunn Источник Размещён: 25.02.2012 11:34

Ответы (5)


1 плюс

7266 Репутация автора

Вам нужно передать указатель значения, которое будет обновлено ... например:

// Initialize a configfile structure (0 sections)
void init_file(configfile **cf) {
    *cf = malloc(sizeof(configfile));
    (*cf)->numsections = 0;
}

configfile *var;
init_file(&var);
printf("%d\n", var->numsections);

В противном случае вы просто обновляете локальный указатель * cf, а не оригинал, переданный в значении

Автор: Geoffrey Размещён: 25.02.2012 11:38

2 плюса

8152 Репутация автора

Вы ни в коем случае не инициализируете cf->sections, что означает, что при reallocпервой попытке вы пропускаете мусор. Добавление:

 cf->sections = NULL;

чтобы init_fileпомочь.

Вы также не проверяете коды возврата, но знаете, что да?

Автор: Tim Размещён: 25.02.2012 11:43

2 плюса

49916 Репутация автора

Решение

Эта рутина должна быть

void init_file(configfile **cf) { 
    *cf = malloc(sizeof(configfile)); 
    (*cf)->numsections = 0;
    (*cf)->sections = NULL; // You forgot to initialise this.
}

т.е. вызывается init_file(&myconfigfilepointer);так, mallocвозвращаемое значение передается обратно.

Нужно сделать такой же трюк для init_sec

Эта функция неверна - здесь исправленная версия

void add_sec(configfile *cf, configsection *sec) {     
    // Increase the size indicator by 1     
    // Reallocate the array to accommodate one more item     
    cf->sections = realloc(cf->sections, sizeof(configsection)*(1 + cf->numsections));     
    // Insert the new item     
    cf->sections[cf->numsections] = *sec; // Since arrays start at 0     
    cf->numsections = cf->numsections + 1;     
} 

Затем вам нужно настроить вызовы в main

Автор: Ed Heal Размещён: 25.02.2012 11:44

1 плюс

137999 Репутация автора

Да, есть проблема в init_sec

// Initialize a configsection structure with a name (and 0 options)
void init_sec(configsection *sec, char *name) {
    sec = malloc(sizeof(configsection));
    sec->numopts = 0;
    sec->name = name;
    printf("%s\n", sec->name);
}

Вы просто копируете указатель имени здесь, что означает, что он указывает на оригинальное хранилище имени. Если бы вы позвонили init_secтак

configsection foobar()
{
    configsection sec;
    char name[80];

    get_name(name);
    init_sec(sec, name);
    return sec;    
}

nameУказатель стал недействительным момент foobarвернулся. Вам нужно продублировать строку и сохранить вашу личную копию. В init_sec:

    sec->name = strdup(name);

Но это еще не все. В самой первой строке init_secвы перезаписываете указатель, который был передан указателю init_secmalloc. Таким образом, новый указатель никогда не передается обратно в вызов. Либо используйте указатель на указатель, вообще не берите указатель configsection (в конце концов, вы выделяете), а просто возвращайте выделенный указатель: Завершите исправленную функцию:

// Initialize a configsection structure with a name (and 0 options)
configsection* init_sec(char *name) {
    configsection *sec = malloc(sizeof(configsection));
    sec->numopts = 0;
    sec->name = name;
    printf("%s\n", sec->name);
    return sec;
}
Автор: datenwolf Размещён: 25.02.2012 11:53

1 плюс

385495 Репутация автора

Вам нужно по-настоящему переосмыслить, как аргументы функции передаются в C и каковы указатели. Ваша проблема не имеет ничего общего с распределением памяти. Скорее, ваш код назначает указатель динамически распределенной памяти только на локальную переменную , о которой вызывающий код ничего не знает.

Хотя вы можете решить проблему, передав указатель на указатель вызывающей стороны (то есть двойной указатель), это не обязательно самый элегантный или самый обычный способ обработки вещей. Скорее, вы должны вернуть результат выделения из функции. Пока вы работаете над этим, вы также callocдолжны сразу обнулять память. Завершение всего этого:

typedef struct substuff_
{
    int a;
    double b;
} substuff;

typedef struct stuff_
{
    unsigned int n;
    substuff * data;
} stuff;

substuff * init_substuff()
{
    substuff * const p = malloc(sizeof *p);
    if (p) { p->a = 5; p->b = -0.5; }
    return p;
}

stuff * init_stuff()
{
    substuff * const p = init_substuff();
    if (!p) return NULL;

    stuff * const q = malloc(sizeof *q);
    if (q) { q->n = 10; q->data = p; }
    return q;
}

В качестве упражнения вы должны написать соответствующие функции void free_substuff(substuff *)и void free_stuff(stuff *).

Автор: Kerrek SB Размещён: 25.02.2012 12:04
Вопросы из категории :
32x32