Назначение памяти двойному указателю?
У меня возникли проблемы с пониманием того, как назначать память
к двойному указателю.
Я хочу прочитать массив строк и сохранить его.
char **ptr;
fp = fopen("file.txt","r");
ptr = (char**)malloc(sizeof(char*)*50);
for(int i=0; i<20; i++)
{
ptr[i] = (char*)malloc(sizeof(char)*50);
fgets(ptr[i],50,fp);
}
вместо этого я просто назначаю большой блок памяти и
сохранить строку
char **ptr;
ptr = (char**)malloc(sizeof(char)*50*50);
было бы неправильно? И если да, то почему?
Ответы
Ответ 1
Ваш второй пример неверен, потому что каждое место памяти концептуально не будет содержать char*
, а скорее char
. Если вы слегка измените свое мышление, это может помочь в этом:
char *x; // Memory locations pointed to by x contain 'char'
char **y; // Memory locations pointed to by y contain 'char*'
x = (char*)malloc(sizeof(char) * 100); // 100 'char'
y = (char**)malloc(sizeof(char*) * 100); // 100 'char*'
// below is incorrect:
y = (char**)malloc(sizeof(char) * 50 * 50);
// 2500 'char' not 50 'char*' pointing to 50 'char'
Из-за этого ваш первый цикл будет таким, как вы делаете в C массив массивов символов/указателей. Использование фиксированного блока памяти для массива массивов символов в порядке, но вы бы использовали один char*
, а не char**
, так как у вас не было бы указателей в памяти, просто char
s.
char *x = calloc(50 * 50, sizeof(char));
for (ii = 0; ii < 50; ++ii) {
// Note that each string is just an OFFSET into the memory block
// You must be sensitive to this when using these 'strings'
char *str = &x[ii * 50];
}
Ответ 2
другой более простой способ запомнить
Случай -1:
step-1: char * p;
Шаг -2:
пожалуйста, прочитайте его ниже
char (* p); == > p является указателем на char
теперь вам просто нужно сделать malloc для типа (шаг-2) без брекетов
i.e., p = malloc (sizeof (char) * some_len);
Случай -2:
step-1: char ** p;
Шаг -2:
пожалуйста, прочитайте его ниже:
char * (* p); == > p является указателем на char *
теперь вам просто нужно сделать malloc для типа (шаг-2) без брекетов
i.e., p = malloc (sizeof (char *) * some_len);
Случай -3:
Никто не использует это, а просто для объяснения
char *** p;
прочитайте его как
char ** (* p); == > p является указателем на char ** (и для этого чек-2 выше)
p = malloc (sizeof (char **) * some_len);
Ответ 3
Двойной указатель - это просто указатель на другой указатель. Поэтому вы можете выделить его следующим образом:
char *realptr=(char*)malloc(1234);
char **ptr=&realptr;
Вы должны помнить, где хранится ваш указатель (в этом примере двойной указатель указывает на переменную-указатель в стеке, поэтому он недействителен после возвращения функции).
Ответ 4
Добавляя к Пентам ответ, как он правильно указал, вы не сможете использовать этот двойной указатель после возвращения функции, поскольку он укажет на ячейку памяти в записи активации функции в стеке, которая теперь устарела (один раз функция вернулась). Если вы хотите использовать этот двойной указатель после возвращения функции, вы можете сделать это:
char * realptr = (char *) malloc(1234);
char ** ptr = (char **) malloc(sizeof(char *));
*ptr = realptr;
return ptr;
Возвращаемый тип функции должен быть char **
для этого.
Ответ 5
Двойной указатель, просто поместите, указатель на указатель,
Во многих случаях он используется как массив других типов.
Например, если вы хотите создать массив строк, вы можете просто сделать:
char** stringArray = calloc(10, 40);
это создаст массив размером 10, каждый элемент будет строкой длиной 40.
таким образом вы можете получить доступ к этому с помощью stringArray [5] и получить строку в 6-й позиции.
это одно использование, остальные - как указано выше, указатель на указатель и могут быть распределены просто:
char* str = (char*)malloc(40);
char** pointerToPointer = &str //Get the address of the str pointer, valid only in the current closure.
читайте здесь:
хорошее руководство по массиву