it-swarm.com.ru

Назначение памяти двойному указателю?

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

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

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

12
lazy_hack

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

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];
}
12
user7116

я приведу один пример, который может очистить от сомнения,

char **str;                              // here its kind a equivalent to char *argv[]
str = (char **)malloc(sizeof(char *)*2)  // here 2 indicates 2 (char*)
str[0]=(char *)malloc(sizeof(char)*10)   // here 10 indicates 10 (char)
str[1]=(char *)malloc(sizeof(char)*10)   // <same as above>

strcpy(str[0],"abcdefghij");   // 10 length character 
strcpy(str[1],"xyzlmnopqr");   // 10 length character

cout<<str[0]<<endl;    // to print the string in case of c++
cout<<str[1]<<endl;    // to print the string in case of c++

or

printf("%s",str[0]);
printf("%s",str[1]);  

//finally most important thing, dont't forget to free the allocated mem
free(str[0]);
free(str[1]);
free(str);
2
Abhishek D K

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

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

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

1
Pent Ploompuu

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

Случай 1 :

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

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

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

теперь вам просто нужно сделать malloc для типа (шаг-2) без фигурных скобок

то есть p = malloc (sizeof (char) * some_len);

Дело -2:

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

шаг 2 :

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

char * (* p); ==> p - указатель на символ *

теперь вам просто нужно сделать malloc для типа (шаг-2) без фигурных скобок

то есть p = malloc (sizeof (char *) * some_len);

Дело -3:

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

char *** p;

читать как

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

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

1
ravi chandra
 char **ptr;
    fp = fopen("file.txt","r");
    ptr = (char**)malloc(sizeof(char*)*50);
    for(int i=0; i<50; i++)
    {
       ptr[i] = (char*)malloc(sizeof(char)*50);
       fgets(ptr[i],50,fp);
    }

fclose(fp);

может быть ваша ошибка опечатки, но ваш цикл должен быть 50 вместо 20, если вы ищете матрицу 50 х 50. Также после выделения памяти, упомянутой выше, вы можете получить доступ к буферу как ptr [i] [j], т.е. в формате 2D. 

1
AnkitSahu

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

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

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

0
Rohan Saxena