Динамическое выделение памяти для массивов указателей

Я пытаюсь написать программу, которая считывает ряд строк из текстового файла и сохраняет их в массиве строк, динамически выделяя память для каждого элемента. Мой план состоял в том, чтобы хранить каждую строку в массиве с помощью указателя, а затем увеличивать размер массива по мере чтения. Мне трудно понять, почему мой тестовый код ниже не работает. Это рабочая идея?

char *aPtr;
aPtr =(char*)malloc(sizeof(char));

aPtr[0]="This is a test";


printf("%s",aPtr[0]);

person user2826534    schedule 28.09.2013    source источник
comment
Это не работает, потому что вы malloc ставите пробел для одного символа, а затем пытаетесь присвоить целую строку char-типу lvalue.   -  person Fred Foo    schedule 28.09.2013
comment
Рекомендуемое чтение: Когда следует использовать malloc в C, а когда нет?.   -  person haccks    schedule 28.09.2013


Ответы (4)


В C строка представляет собой char*. Динамический массив типа T представлен как указатель на T, поэтому для char* это будет char**, а не просто char*, как вы его объявили.

Компилятор, без сомнения, выдал некоторые предупреждения об этом. Обратите внимание на эти предупреждения, очень часто они помогают понять, что делать.

Вот как вы можете начать тестирование:

char **aPtr;
int len = 1; // Start with 1 string
aPtr = malloc(sizeof(char*) * len); // Do not cast malloc in C
aPtr[0] = "This is a test";
printf("%s",aPtr[0]); // This should work now.
person Sergey Kalinichenko    schedule 28.09.2013
comment
Чтобы проверить (пожалуйста, потерпите меня, я новичок =]), если вам нужен динамический массив указателей на char (например, по мере необходимости в приложении, где вам может потребоваться хранить строки символов с переменным числом, например, при чтении текстовый файл, не зная его длины или собирая пользовательский ввод неопределенной длины), тогда вам понадобится динамический массив Char*, а значит, вам понадобится Char**. char** может указывать на разные указатели символов, которые могут быть начальным адресом разных строк символов. - person Minh Tran; 12.09.2015
comment
для чего здесь len=1? Похоже, что This is a test будет состоять из 14 символов, каждый из которых представляет собой байт.... но в этом коде не упоминается 14, и при запуске он не segfault. - person nmz787; 08.02.2017
comment
@nmz787 nmz787 Обратите внимание на тип aPtr, это двойной указатель, поэтому он представляет собой массив указателей на символы. Затем указатель char устанавливается в нулевой элемент; в этом коде не происходит копирования строк. - person Sergey Kalinichenko; 08.02.2017

char *str; //single pointer   

При этом вы можете сохранить одну строку.


Для хранения array of strings нужно two dimensional character array

или еще array of character pointers или еще double pointer


char str[10][50]; //two dimensional character array

Если вы объявляете так, вам не нужно выделять память, так как это статическое объявление


char *str[10];  //array of pointers 

Здесь нужно выделить память для каждого указателя

цикл через массив для выделения памяти для каждого указателя

for(i=0;i<10;i++) 
str[i]=malloc(SIZE);

char **str;    //double pointer

Здесь вам нужно выделить память для количества указателей, а затем выделить память для каждого указателя.

str=malloc( sizeof(char *)*10);

И затем цикл через массив выделяет память для каждого указателя

for(i=0;i<10;i++) 
str[i]=malloc(SIZE);
person Gangadhar    schedule 28.09.2013

char * aPtr;

является указателем на символ, которому вы выделили память для хранения ровно 1 символа.

Делает

aPrt[0] = "test";

вы обращаетесь к памяти для этого one символа и пытаетесь сохранить в ней адрес литерала "test". Это не удастся, так как этот адрес, скорее всего, шире символа.

Исправление вашего кода будет заключаться в выделении памяти для указателя на символ.

char ** aPtr = malloc(sizeof(char *));
aPtr[0] = "test";
printf("%s", aPtr[0]);

Более элегантным и более надежным подходом было бы выделить то же самое (а также добавить обязательную проверку ошибок), выполнив:

char ** aPtr = malloc(sizeof *aPtr);
if (NULL == aPtr)
{
  perror("malloc() failed");
  exit(EXIT_FAILURE);
}

...
person alk    schedule 28.09.2013

Вы делаете это совершенно неправильно. Правильная версия вашего кода должна быть такой:

int main ()
{
char *aPtr;
aPtr =(char*)malloc(20*sizeof(char));
aPtr ="This is a test";
printf("%s",aPtr);
}

Вы можете использовать массив указателей. если вы хотите сохранить несколько строк. Да, я знаю, что использовать цикл for будет легко. Но я пытаюсь объяснить простым языком, понятным даже новичку.

int main ()
{
char *aPtr[10];
aPtr[0] =(char*)malloc(20*sizeof(char));
aPtr[0] ="This is a test";
aPtr[1] =(char*)malloc(20*sizeof(char));
aPtr[1] ="This is a test2";
printf("%s\n%s\n",aPtr[0],aPtr[1]);
 }
person Tonmoy    schedule 28.09.2013
comment
В вашем первом примере происходит утечка памяти, а именно 20 байт. Выполняя aPtr ="This is a test";, вы теряете ссылку на то, что вернул malloc(). Эта память никогда не использовалась и никогда не будет использоваться во время работы программы. - person alk; 28.09.2013
comment
sizeof(char)является 1 определением. Приведение результата malloc/calloc/realloc не требуется в C и не рекомендуется: stackoverflow.com/a/605858/694576 - person alk; 28.09.2013
comment
Спасибо всем ответившим очень помогли - person user2826534; 29.09.2013