2013-09-14 3 views
0

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

Код вращается вокруг настройки различных панелей, окон и связанных с ними заголовков. Именно это распределение памяти для строки заголовка, с которой у меня возникают проблемы.

Основание представляет собой структуру, которая содержит:

struct TFB_PANEL 
{ 
    WINDOW *window; 
    char *title; 
}; 

Это typedef'd в заголовочном файле как:

typedef struct TFB_PANEL TfbPanel; 

В соответствующем файле C У меня есть следующий метод, который инициализирует массив TFB фиксированного размера.

int tfb_init() 
{ 
    if (!_initialised) { 
     return -1; 
    } 

    int i; 
    for (i = 0; i < TYPE_MAX; i++) { 
     TFB[i] = malloc(sizeof(TfbPanel*)); 
     TFB[i]->title = calloc((strlen(TYPES[i]) + 18), sizeof(char*)); 
     switch(i) 
     { 
      case A: 
       sprintf(TFB[i]->title, " %s | r | h | s | t ", TYPES[i]); 
       break; 
      case B: 
       sprintf(TFB[i]->title, " f | %s | h | s | t ", TYPES[i]); 
       break; 
      case C: 
       sprintf(TFB[i]->title, " f | r | %s | s | t ", TYPES[i]); 
       break; 
      case D: 
       sprintf(TFB[i]->title, " f | r | h | %s | t ", TYPES[i]); 
       break; 
      case E: 
       sprintf(TFB[i]->title, " f | r | h | s | %s ", TYPES[i]); 
       break; 
     } 

     TFB[i]->window = tfb_create_window(i); 
    } 
    return 0; 
} 

Теперь ошибка возникает, когда C инициализируется. A и B правильно установлены на длину 25 символов. С другой стороны должно содержать 24 символов после инициализации, но вместо этого (в пределах от tfb_create_window) Я получаю

Program received signal EXC_BAD_ACCESS, Could not access memory 
Reason: 13 at address 0x0000000000000000 
0x00007fff930b9390 in strcmp() 

Исследование показывает стек ТФБ [С] инициализируется правильно, но заголовок элемента нет. Он содержит нулевой элемент, как если бы я никогда не вызывал calloc.

Пожалуйста, объясните, где я ошибаюсь, или почему A и B инициализируются правильно, но C убивает приложение. Все прошло красиво до 6 утра этим утром, с тех пор он спустился вниз.

Если это помогает, tfb_create_window определяется с помощью вызова _create_window и вызова tfb_get_title следующим образом:

char *tfb_get_title(int type) 
{ 
    if (type >= TFB_MAX) { 
     return (char*)NULL; 
    } 
    return TFB[type]->title; 
} 

WINDOW *tfb_create_window(int type) 
{ 
    int height = ((LINES - WIN_OFFSET_Y)/3); 
    char *title = tfb_get_title(type); 
    return _create_window(height, WIN_SIDEBAR_X, WIN_OFFSET_Y, 0, COLOUR_MAIN, title); 
} 

WINDOW *_create_window(int height, int width, int starty, int startx, int color, const char *title) 
{ 
    WINDOW *window; 
    window = newwin(height, width, starty, startx); 
    box(window, 0, 0); 
    mvwprintw(window, 0, 2, title); 
    wbkgd(window, COLOR_PAIR(color)); 
    return window; 
} 
+2

Это не ваша проблема, но обратите внимание, что вы на самом деле выделяете слишком много памяти в один момент: 'calloc ((strlen (TYPES [i]) + 18), sizeof (char *))'. Это выделяет пространство для '(strlen (TYPES [i]) + 18' char _pointers_, что, вероятно, в 4 или 8 раз больше, чем вам нужно. – svk

+0

Я думал, что я изначально выделял только« strlen (TYPES [ i]) + 18', но я добавил множитель, пытаясь его исправить. Я также попытался использовать 'malloc (strlen (TYPES [i]) + 18), но безрезультатно. – mplf

+1

@mplf Вы уверены, что хочу сделать это 'malloc (sizeof (TfbPanel *))' вместо 'malloc (sizeof (TfbPanel))'? Также, что такое 'TFB [i]'? –

ответ

1

В этом коде есть ряд ошибок, наиболее серьезным является то, что вы используете sizeof(Type*) вместо sizeof(Type). Более поздний - фактический размер объекта, первый - это только размер указателя на этот объект (который составляет 8 байтов на 64-битных машинах).

Это означает, что malloc(sizeof(TfbPanel*)) выделяет слишком мало памяти для вашего TfbPanel, поэтому остальная часть программы имеет неопределенное поведение.

calloc() ошибочен тем же способом, но некритично, потому что вы выделяете в восемь раз больше памяти, сколько вам нужно.

Однако calloc() вызова имеет другую ошибку: добавить 18 к результату strlen(), что количество полезной нагрузки символов, которые вы добавляете в ваших sprintf() вызовов. Это слишком мало, потому что результат strlen() не включает нулевой байт.

Если вы можете использовать совместимый Libc POSIX-2008 (как в Glibc на системах Linux), вы можете использовать asprintf() вместо sprintf(), он будет автоматически таНос достаточно мест для результирующей строки, избегая возможные ошибки размера буфера. Если вы не можете использовать эту функцию, используйте не менее snprintf(), чтобы избежать доступа к нераспределенной памяти.

+0

На основе комментариев до сих пор я уже поменял назначение' malloc (sizeof (TfbPanel *)) 'для использования' malloc (sizeof (struct TfbPanel)) '- ключевой вопрос, который вы правильно указали, - это слишком мало символов для строки. Я добавил это, и он разрешен. Спасибо. – mplf

0

Если вы пошагово с помощью GDB на этой линии:

sprintf(TFB[i]->title, " f | r | %s | s | t ", TYPES[i]); 

Что значения TYPES [i]?

+0

TYPES - это фиксированный массив, определяемый как char * TYPE [] = {"feature", "release", "hotfix", "support", "trunk"}; – mplf

+0

Какова ценность 'TYPE_MAX'? – varnie

+0

'enum' от A - TYPE_MAX, соответствующего значениям ключа из массива TYPE – mplf

Смежные вопросы