Несоответствие указателя для фактического параметра? - PullRequest
1 голос
/ 01 сентября 2010

У меня есть функция, которая создает массив указателей.Функция, которая выделяет память, возвращает новый указатель памяти через параметр, переданный функции.Простейший код, который может воспроизвести проблему, выглядит следующим образом:

void foo (void** new_mem, size_t bytes)
{
    *new_mem = malloc(bytes);
}

int main (void)
{
    int** ptr_arr; // Want to create an array of pointers

    foo(&ptr_arr, sizeof(int*)*100); // Create an array size of 100
                                     // compiler emits warning: 
                                     // 'void **' differs in levels of indirection from 'int ***'

    return 0;
}

Я мог бы привести первый параметр, переданный в foo, примерно так: '(void **) & ptr_arr', однако, чтобы избавиться от предупреждения,Мне интересно: есть ли более подходящее решение?

Ответы [ 3 ]

0 голосов
/ 01 сентября 2010

Проблема в том, что ptr_arr уже является int **,, когда вы делаете &ptr_arr, оно будет отображаться как int ***, поэтому то, что вы делаете, неверно.

Итак, вы можете просто передать ptr_arrесли вы намереваетесь передать int **

Кроме того, я чувствую, что ваш код может хорошо справиться с очисткой.Ваш подход кажется неправильным.

0 голосов
/ 01 сентября 2010

Хотя существует гарантированное преобразование из int * в void *, такой гарантии для преобразования из int ** в void ** не существует. Чтобы подумать, почему это может быть, учтите, что int * может на самом деле быть меньше, чем void *. В результате, использование указателя void ** для обхода массива int * s приведет к неверному шагу и получит неверные данные. Более того, нет никакой гарантии, что int * будет использовать то же представление, что и void *, только что существует способ конвертации между ними.

На практике я не знаю ни одной машины, где это не получится. Но это не гарантируется стандартом.

РЕДАКТИРОВАТЬ: eek, и что все говорят о прохождении int ***. Но даже если вы передадите int **, вышеприведенное применимо.

EDIT2: в FAQ по comp.lang.c содержится превосходное обсуждение об этом.

0 голосов
/ 01 сентября 2010

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

Приведение результата к void** будет работать технически, хотя это граничит со злоупотреблением системой типов.

...