Выделить массив 2D-символов malloc или calloc

Недавно я решил освежить свои знания C (то немногое, что у меня осталось). Я довольно быстро понял, что первым навыком, который стал туманным, было управление памятью. Проклятый.

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

Упрощенная версия этого кода:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    char **aStr = malloc(4*sizeof(aStr));
    int j = 0;
    int i = 0;
    while(i<sizeof(aStr))
    {
        j = 4 + 2*i;//in my code, length is determined by arguments
        aStr[i] = malloc(j*sizeof(aStr[i]));
        j--;
        strncpy(aStr[i],"RaisinRubarbCarrot"+i,j);
        aStr[i][j] = 0;//just a habbit
        j++;
        printf("ptr@:%p\n\tkey:%d\n\tval:%s\n\tlength:%d (%d)\n\n",*aStr[i],i,aStr[i],j,strlen(aStr[i]));
        i++;
    }
    free(aStr);
    return 0;
}

Я чувствовал, что это было неуклюжим и нелогичным. Сегодня я вспомнил своего старого врага: calloc. потом я написал

char **aStr = (char **)calloc(4, sizeof(char *));

и в цикле:

aStr[i] = (char *) calloc(j,sizeof(char *));

Я нашел примеры кода, которые записывают последнюю строку так:

aStr[i] = (char *) calloc(j,sizeof(char));//without the asterisk

Вопрос 1: в чем разница, если есть?

Вопрос 2: Нет ли другого способа размещения массива строк? то, как я вижу код сейчас, кажется/выглядит так, будто я сначала выделяю 4 указателя на один указатель char, а затем выделяю фактический размер, необходимый для каждого указателя. Это просто кажется неправильным.

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


person Elias Van Ootegem    schedule 13.08.2012    source источник
comment
aStr[i] = (char *) calloc(j,sizeof(char)); не sizeof(char *)   -  person Gir    schedule 14.08.2012
comment
@Gir, я так и думал, как ни странно, оба компилируются нормально, никаких предупреждений не выдается   -  person Elias Van Ootegem    schedule 14.08.2012
comment
так? я не имею в виду, что это правильно. он не жалуется, потому что а) вы приводите оба результата к правильному типу б) он не знает, что вы хотите сделать. я даже не уверен, что вам нужно бросать   -  person Gir    schedule 14.08.2012
comment
@Gir: sizeof(char) равно 1 по определению, и вам не следует разыгрывать. Так что это должно быть только aStr[i] = calloc(j, 1);.   -  person Kerrek SB    schedule 14.08.2012
comment
sizeof(char) может быть более читабельным   -  person Gir    schedule 14.08.2012


Ответы (2)


char * и char — это два разных типа и разные размеры данных. char всегда представляет собой один байт, поэтому sizeof(char) всегда равно 1. С другой стороны, указатель на char будет занимать 4 байта в 32-битной системе. Поэтому, если вы используете sizeof(char*) для выделения места для строки, вы будете выделять гораздо больше, чем вам нужно.

Использование цикла для выделения отдельных строк в порядке. Предполагая максимальную длину ваших строк, вы можете просто выделить один большой блок, но это будет неуклюже.

person pb2q    schedule 13.08.2012
comment
Так какой же из двух способов предпочтительнее? calloc или malloc, потому что в обоих случаях код делает одно и то же. В настоящее время я использую calloc, потому что он лучше соответствует цели IMO - person Elias Van Ootegem; 14.08.2012
comment
calloc инициализирует элементы данных нулями для вас, что может предотвратить определенные ошибки. В остальном они эквивалентны: просто используйте тот, который, по вашему мнению, читается лучше. Но если вы используете malloc, имейте в виду, что память ничем не инициализирована и будет заполнена ненужными данными. - person pb2q; 14.08.2012

  1. Вы должны использовать sizeof(char) вместо sizeof(char*), потому что вы пытаетесь выделить память для массива символов, а не для массива указателей на символы. Итак, правильная версия:

    aStr[i] = (char*) calloc(j, sizeof(char)); 
    //first argument number of memory
    //locations to be allocated
    //second argument, size of each location
    

    Отличие/преимущество calloc по сравнению с malloc заключается в том, что он также инициализирует ячейки памяти равными 0.

  2. Сначала вы выделяете массив из 4 указателей на символы. И затем вы выделяете память для каждой из строк (каждый из 4 ранее выделенных указателей будет указывать на один из этих массивов)

person Razvan    schedule 13.08.2012
comment
sizeof(char) == 1 однако. - person mirabilos; 01.04.2014