Я думаю, что ваша проблема в этом коде:
scanf("%9s", NameList[0]);
Проблема здесь в том, что scanf
требует, чтобы аргумент, который вы указываете в качестве местоположения для хранения результата, должен быть указателем.Если вы предоставляете что-то, что не является указателем, scanf
будет обрабатывать его так, как если бы оно было, и, по сути, записывать память в случайное место, что приведет к сбою программы.
Исправление этого требует двух шагов.Во-первых, вы захотите изменить объявление NameList
, чтобы оно больше не char *
.Причина в том, что char *
является одиночной строкой, тогда как вам нужен массив строк.Это будет определено как char **
, указатель на массив char *
s.Это может выглядеть так:
char** NameList;
Далее вам нужно выделить место для хранения строк.Это сложно и немного неуловимо, потому что вам нужно сделать два распределения.Во-первых, вам нужно выделить место для самого массива, что вы можете сделать следующим образом:
NameList = malloc (sizeof(char*) * NumItems);
Это выделяет массив указателей на символы, но фактически не устанавливает указатели в этих массивах.указать на действительные места в памяти.Чтобы это исправить, вам нужно будет выполнить итерацию по всему массиву и установить все его элементы в качестве указателей на буферы, достаточно большие для хранения ваших строк - в данном случае это буферы длиной 10:
int i;
for (i = 0; i < NumItems; ++i)
NameList[i] = malloc (10); // Space for 10 characters
Теперь вы можете вызвать
scanf("%9s", NameList[0]);
Поскольку NameList[0]
- это char *
, указывающий на буфер, в который должны быть записаны символы.
Еще один комментарий к вашему коду - вместовыделив массив из одного элемента, а затем перераспределив его в массив из двух элементов, рассмотрите возможность выделения всего пространства заранее.Это немного понятнее.Кроме того, поскольку теперь вы имеете дело с буфером char *
s, каждый из которых необходимо инициализировать, чтобы он указывал на свой собственный буфер, если вы выполняете инкрементное распределение, вам необходимо обязательно инициализировать все новые char *
s, которые вы выделяете, чтобы указать где-нибудь буфер.Если вы делаете это по одному шагу за раз, есть хороший шанс, что вы забудете установить указатели и вызвать сбой, тогда как если вы сделаете это заранее, такого риска нет.
Когда придет времяОсвободив динамически распределенную память, вам нужно будет выполнить процесс выделения в обратном порядке, сначала освободив динамически распределенные буферы для строк, а затем освободив буфер верхнего уровня.Например:
for (i = 0; i < NumItems; ++i)
free (NameList[i]);
free (NameList);
Это необходимо, потому что free
не работает рекурсивно.Вам нужно явно освободить всю память, которую вы выделяете.
Обратите внимание, что вы не пишете код следующим образом:
free (NameList);
for (i = 0; i < NumItems; ++i)
free (NameList[i]);
Это вызовет все видыПлохие вещи во время выполнения, потому что если вы сначала освободите массив верхнего уровня, а затем попытаетесь перебрать его содержимое, освобождая указатели, вы будете читать память, которой вы больше не владеете.
Надеюсь, это поможет!