Можно ли передать char [] [] в функцию, запрашивающую char **? - PullRequest
3 голосов
/ 04 декабря 2011

Я пытаюсь вызвать функцию, которая принимает char ** в качестве параметра.Его работа заключается в заполнении массива строк (то есть массива char *).Я знаю максимальную длину строк, и я могу передать максимальное число для заполнения в качестве другого параметра, поэтому я надеялся разместить его в стеке следующим образом:

fill_my_strings(char** arr_str, int max_str); // function prototype

char fill_these[max_strings][max_chars_per_string]; // allocating chars
fill_my_strings(fill_these, max_strings); // please fill them!

Конечно, я получаю «не могу»конвертировать char [max_strings] [max_chars_per_string] в char ** "ошибка.

Я знаю, что это какая-то тонкая (или не очень тонкая) проблема с моим пониманием разницы между массивами и указателями.Я просто не уверен, почему невозможно передать этот блок памяти чему-то, требующему символа **, и заставить его заполнить мои выделенные стеком символы.Может кто-нибудь объяснить, если это возможно, а если нет, то почему нет?

Можно ли вызвать такую ​​функцию без вызова malloc / new?

Ответы [ 4 ]

3 голосов
/ 04 декабря 2011

Простой ответ на ваш вопрос - нет; Двумерный массив отличается от указателя на тип указателя. Массивы распадаются на указатели на их первый элемент, но указатели на самом деле это значение.

Разница между этими типами очевидна, если вы приведете оба к char*

int x;
char *arr_pp[] = {"foo", "bar", "baz"};
char arr_2d[][4] = {"foo", "bar", "baz"};

char *cp = (char*)arr_pp;
for(x=0; x<3; x++)
     printf("%d ", cp[x]);
printf("\n");

cp = (char*)arr_2d;  
for(x=0; x<3; x++)
     printf("%d ", cp[x]);
printf("\n");

Вывод (на моем компьютере):

-80 -123 4 
102 111 111 

Где первая строка - бред, сформированный тем фактом, что я печатаю адрес, приведенный в байтах, а вторая строка - значения ascii для "foo".

В функции, принимающей char **, компилятор не может распознать типы массивов, которые на самом деле не содержат указателей.

2 голосов
/ 04 декабря 2011

Предположим, у вас есть n указателей на строки максимум из m-1 символов (m символов, включая NULL).Таким образом, в чистом C: sizeof (char [n] [m]) вернет n * m.sizeof (char **) вернет размер указателя в вашей архитектуре, вероятно, 32 (если x86) или 64 (если x86_64).

char [n] [m] фактически выделяет байт n * mсмежно.char ** выделяет один указатель.Этот указатель ссылается на полосу памяти размером * n байт.Каждый из этих n указателей указывает на полосу памяти из m символов.

Итак, учитывая, что sizeof (char) == u, если вы объявляете char a [n] [m], когда вы используете [i] [j], компилятор понимает * (a + i * m * u + j * u).Итак, учитывая, что sizeof (char *) == w, если вы объявляете char ** a, когда вы используете [i] [j], компилятор понимает ( (a + i * w) +j * w).

Полностью другое управление данными.

Закрытие, которое вы могли бы сделать для обработки вашего особого случая, - это создать переменную char ** и заполнить ее адресами вашеговыделенная матрица стека.

char **tmp = malloc(max_strings * sizeof(char *));
int i;
for(i = 0; i < max_strings; i++){
    tmp[i] = &(fill_these[i][0]); //you probably can't reference a char[][] with a single index - not confirmed
}
2 голосов
/ 04 декабря 2011

Я не уверен, зачем fill_my_strings () нужен параметр char**.Из вашего примера вызывающая программа уже выделила память из стекаТак что использование char* должно быть в порядке.

Но если вы хотите использовать char** или не можете изменить функцию fill_my_strings(), попробуйте следующий пример кода:

void fill_my_strings(char** arr_str, int max_chars_per_string, int max_strings)
{

    for(int i = 0; i < max_strings; ++i)
    {
        //Make sure you have enough space
        memcpy(*arr_str, "ABCD", sizeof("ABCD"));

        *arr_str += max_chars_per_string;
    }
}

char fill_these[max_strings][max_chars_per_string];
char* pointer = (char*)fill_these;
fill_my_strings(&pointer, max_strings, max_chars_per_string);
0 голосов
/ 04 декабря 2011

Очевидная вещь, которую нужно сделать - это построить индекс

В c можно использовать что-то вроде:

char string_list[num_strings][str_length];

// ...

char**index = calloc( (num_strings+1), sizeof(*index) ); // calloc insures NULL termination
for (int i=0; i<num_strings; ++i) {
   index[i] = string_list[i]
}

В c ++ предпочитают new[] calloc;

...