Простое решение, используйте strdup
, если оно у вас есть
Ваша проблема заключалась в том, что вы выделяли только 20
указатели.Выделенные указатели неинициализированы и сами по себе не указывают на какое-либо действительное хранилище.Чтобы хранить строки в каждом указателе s[i]
, необходимо выделить хранилище, достаточное для хранения ss
(strlen(ss) + 1
символов), а затем скопировать ss
в новый выделенный вами блок памяти.Если у вас есть функция strdup
, которая будет выделять и копировать для вас, но, поскольку она выделяет, вы можете подтвердить распределение успешно выполнено, например,
#define NPTR 20 /* if you need a constant, #define one (or more) */
int main (int argc, char *argv[])
{
char **s = NULL; /* initialize all variables */
char ss[20] = "";
int i = 0,
ret = 0;
s = malloc (NPTR * sizeof *s); /* allocate NPTR pointers to char */
if (s == NULL) { /* validate EVERY allocation */
perror ("malloc-s");
return 1;
}
/* fill up to NPTR pointers with strings read from stdin */
while (i < NPTR && scanf ("%19s", ss) == 1) {
/* compare for stop */
if (strcmp (ss, "stop") == 0)
break;
/* strdup will allocate for s[i] and copy ss */
s[i] = strdup (ss);
if (s[i] == NULL) { /* it allocates -> you must validate */
perror ("strdup-s[i]");
break;
}
i++;
}
}
( примечание: вы должны защитить границы массива для ss
, включив модификатор filed width в ваш вызов scanf
, например, scanf ("%19s", ss)
)
Если у вас нет strdup
, просто malloc
и strcpy
(или лучше memcpy
)
Без strdup
, вы просто получите длину строки вss
, выделите length+1
символов, присваивая начальный адрес для нового блока памяти s[i]
, а затем скопируйте ss
в новый блок памяти.Единственное изменение в приведенном выше:
...
/* fill up to NPTR pointers with strings read from stdin */
while (i < NPTR && scanf ("%19s", ss) == 1) {
size_t len = 0;
/* compare for stop */
if (strcmp (ss, "stop") == 0)
break;
len = strlen (ss); /* get length of string in ss */
s[i] = malloc (len + 1); /* allocate length + 1 chars */
if (s[i] == NULL) { /* you allocate / you validate */
perror ("malloc-s[i]");
break;
}
memcpy (s[i], ss, len + 1); /* you have length, just memcpy */
i++;
}
...
( примечание: выше, вы уже отсканировали ss
в strlen
, чтобы получить длину, поэтому в этом нет необходимости.на strcpy
(который снова будет сканировать конец), просто используйте memcpy
с длиной, которая у вас есть +1
, чтобы скопировать завершающий нуль символ , который будет немного более эффективным).
В любом случае работает.Затем, чтобы освободить выделенную память.
for (int j = 0; j < i; j++)
free (s[j]); /* free storage for each string */
free (s); /* free pointers */
( также обратите внимание: проверка i < NPTR
предотвращает сохранение большего количества строк, чем выделено указателей. Вместо остановки на i == NPTR
, вы можете просто realloc
количество указателей и продолжить. Общий подход состоит в том, чтобы отслеживать количество выделенных вами указателей, а когда вы достигнете своего предела, realloc
, чтобы удвоить количество указателей (илиумножьте текущее число на 3/2
, или как вам угодно), проверьте успешность перераспределения, обновите текущее число, назначенное новому количеству указателей, и продолжайте, пока не достигнете предела указателя снова, и повторите при необходимости ...)