2010-02-13 5 views
10

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

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); 

бы это было не так? И если да, то почему?

+6

Не называйте его «двойным указателем» - это автоматически выводит вас на неправильную ногу - это указатель на указатель. – 2010-02-13 14:17:19

ответ

0

Двойной указатель - это просто указатель на другой указатель. Таким образом, вы можете передать его так:

char *realptr=(char*)malloc(1234); 
char **ptr=&realptr; 

Вы должны иметь в виду, когда указатель хранится в (в этом примере двойных точек указатель на переменную указателя на стек, чтобы он недействителен после возврата из функции) ,

-3

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

Например, если вы хотите создать массив строк, вы можете просто сделать:

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. 

подробнее здесь: good array tutorial

+0

Нет, это создает единый массив из 100 char *, предполагая, что char * занимает 4 байта. –

+0

Что Ганс говорит правильно. Более того, массив из 100 char * инициализируется до 0 (поскольку вы использовали calloc), поэтому все эти char * указывают на null и доступ к этому местоположению массива вызовет ошибку. –

10

Ваш второй пример неправильно, потому что каждая ячейка памяти концептуально не будет содержать 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' 

Из-за этого, ваш первый цикл будет, как вы делаете в массив символьных массивов/указателей. Использование фиксированного блока памяти для массива массивов символов в порядке, но вы бы использовали один 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]; 
} 
+1

не должна быть последней строкой 'char * str = x + (ii * 50)'? – redFur

+2

И не выдавайте результат 'malloc()'! –

1

другой простой способ запомнить

Случай -1:

шаг 1: символ * р;

шаг -2: пожалуйста, прочитать его, как показано ниже

полукокса (* р); ==> р является указателем на голец

Теперь вам просто нужно сделать таНос для типа (шаг 2) без скобок

т.е. р = таНос (SizeOf (Char) * some_len);

чехол -2:

шаг 1: символ ** р;

шаг -2:

пожалуйста, прочитать его, как показано ниже

символ * (* р); ==> р является указателем на символ *

Теперь вам просто нужно сделать таНос для типа (шаг 2) без скобок

т.е. р = таНос (SizeOf (Char *) * some_len) ;

Дело -3:

Никто не использует это, но только ради объяснения

полукокса *** р;

читать, как,

гольца ** (* р); ==> p является указателем на char ** (и для этого чек-2 выше)

p = malloc (sizeof (char **) * some_len);

0

Добавляя к ответу Пента, как он правильно указал, вы не сможете использовать этот двойной указатель, как только функция вернется, потому что он укажет на ячейку памяти в записи активации функции в стеке, которая теперь устарела (как только функция вернется). Если вы хотите использовать этот двойной указатель после того, как функция возвращается, вы можете сделать это:

char * realptr = (char *) malloc(1234); 
char ** ptr = (char **) malloc(sizeof(char *)); 
*ptr = realptr; 
return ptr; 

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