В этом фрагменте кода:
void func(size_t dim, double **ptr){
(*ptr) = malloc(dim * sizeof **ptr);
/* Perform Calculations...*/
}
В чем разница между использованием sizeof **ptr
и sizeof *ptr
? Это сбивает меня с толку. Кажется, нет никакой разницы, когда я имею дело с типами int*
и double*
, но когда я имею дело с chars*
, использование sizeof **ptr
приводит к ошибке сегментации. Не могли бы вы помочь мне с этим?
Заранее спасибо!
Выделение памяти для чего? Какие расчеты делать? Пожалуйста, опубликуйте минимальный воспроизводимый пример.
Указатели внутри оператора sizeof() не оцениваются, скажем, у вас есть это:
int * pointer = malloc(sizeof(* pointer));
То, что вы делаете здесь, это «malloc sizeof pointed type», преимущество в том, что вы можете изменить тип указателя без изменения части sizeof().
Теперь с двойным указателем:
int ** pointer;
// allocate enough space to store a pointer: sizeof(* pointer) <--> sizeof(int *)
pointer = malloc(sizeof(* pointer));
И с этим:
int ** pointer;
// allocate enough space to store an int: sizeof(** pointer) <--> sizeof(int)
pointer = malloc(sizeof(** pointer));
В 64-битной системе первый случай, скорее всего, даст вам 8 байтов, а второй случай - только 4 байта, что может привести к сбою, если вы намеревались использовать 8 байтов.
(*ptr) = malloc(dim * sizeof **ptr);
Вы сохраняете внутри *ptr, который имеет тип double*, так как ptr имеет тип double**. Вы выделяете n*sizeof(double) байт, а не n*sizeof(double*) байт, в вашей системе может быть иначе.
Или, может быть, сбой происходит при доступе к этой памяти.
Параметр ptr
объявлен как
double **ptr
То есть исходный указатель, используемый в качестве аргумента, передается в функцию по ссылке опосредованно через указатель на нее.
Внутри функции вам необходимо присвоить значение исходному указателю посредством разыменования параметра.
(*ptr) = malloc(dim * sizeof **ptr);
Исходному указателю *ptr
должен быть назначен адрес динамически выделяемого массива двойников. Таким образом, разыменование указателя в выражении
sizeof **ptr
вы получите размер объекта типа double
.
Чтобы сделать его более понятным, вы можете использовать, например, промежуточный указатель, например
double *tmp = malloc(dim * sizeof *tmp );
*ptr = tmp;
Что касается типа операнда в выражении sizeof *ptr
, то он имеет тип double *
и выдает размер объекта типа указателя double *
вместо требуемого размера объекта типа double
.
В чем разница между использованием
sizeof **ptr
иsizeof *ptr
?
sizeof *ptr
— это размер шрифта, на который указывает ptr
.
sizeof **ptr
— это размер типа, на который указывает то, на что указывает ptr
.
Объявление double **ptr
говорит, что ptr
является указателем на указатель на double
. Тогда *ptr
— это указатель на double
, поэтому sizeof *ptr
— это размер указателя на double
. А **ptr
— это double
, поэтому sizeof **ptr
размером с double
.
Кажется, нет никакой разницы, когда я имею дело с типами
int*
иdouble*
, но когда я имею дело сchars*
, использованиеsizeof **ptr
приводит к ошибке сегментации.
Если в вашей системе указатель занимает четыре байта, int
— четыре байта, а double
— восемь байтов, то выделение достаточного места для int
или double
также выделяет достаточно места для указателя. Однако выделения места для char
недостаточно для указателя.
На самом деле маловероятно, что это приведет к заметным различиям для одного указателя, так как malloc
обычно работает в блоках по восемь или 16 байтов, поэтому просьба выделить место для char
на самом деле даст достаточно для указателя, несмотря на оптимизацию компилятора. Однако, если вы выделите dim * sizeof **ptr
байт, где ptr
имеет тип char **
, а dim
большой, то будет выделено достаточно места только для dim
char
элементов и недостаточно места для dim
указателей.
Итак, если я правильно понимаю: если я хочу выполнять операции со значением double
, на которое указывает **ptr
, и обновлять значение ptr
вне функции, я должен объявить как (*ptr) = malloc(dim * sizeof **ptr)
, верно?
@Lgcos: Да, это правильно.
Нарушение сегментации будет вызвано кодом, который вы не показали.