Ваш алгоритм разбит на два значимых места
**tab = ...
в теле цикла неверно.Если tab
равно char**
, то *tab
будет char*
, а **tab
будет char
.Присвоение адреса памяти char
должно пометить огромные предупреждения из вашей цепочки инструментов, и если он не увеличит ваши уровни предупреждений или не получит новую цепочку инструментов. - Первоначальный вход в ваше условие while оценивает неопределенные данные.В то время вы выделили необработанную память для
tab[0]
, но пока еще ничего не заполнено.Таким образом, ваша программа вызывает неопределенное поведение .
Помимо вышесказанного, алгоритмы расширения не сложны, и объяснение вашего rubber-duck поможетзначительно, прежде чем писать какой-либо код.При этом вы увидите, что перераспределение массива указателей при каждом новом чтении является дорогостоящим и неэффективным.Алгоритмы геометрического расширения делают это намного лучше.В качестве бонуса исправлены обе вышеуказанные проблемы.
Код
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFLEN 41
#define MAX_STR_FMT "%40s"
int main()
{
char **tab = NULL;
size_t size = 0, capacity = 0;
char str[MAX_BUFLEN];
while (scanf(MAX_STR_FMT, str) == 1 && strcmp(str, "END"))
{
// check for expansion
if (size == capacity)
{
size_t new_capacity = 2 * capacity + 1;
void *tmp = realloc(tab, new_capacity * sizeof *tab);
if (tmp == NULL)
{
perror("Failed to expand dynamic table");
break;
}
// save expanded table, and update capacity
tab = tmp;
capacity = new_capacity;
}
size_t slen = strlen(str)+1;
if ((tab[size] = malloc(slen)) == NULL)
{
perror("Failed to allocate buffer for new string");
break;
}
// copy incoming string; update 'size' to reflect new count
memcpy(tab[size++], str, slen);
}
//
// TODO: use 'tab' holding 'size' pointers.
//
// then free the table
while (size-- > 0)
free(tab[size]);
free(tab);
return 0;
}
Альтернатива: нет указателей на указатели
Если ваша потребность действительно требует выделения фиксированной длины (как показывает ваш код), вам вообще не нужны указатели на указатели (если нет какой-то скрытой повестки дня для чего-то вроде сортировки с заменой указателей) намного более эффективно, чем замена полных строковых буферов).
Код
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFLEN 41
#define MAX_STR_FMT "%40s"
int main()
{
char (*tab)[MAX_BUFLEN] = NULL; // see difference here
size_t size = 0, capacity = 0;
char str[MAX_BUFLEN];
while (scanf(MAX_STR_FMT, str) == 1 && strcmp(str, "END"))
{
// check for expansion
if (size == capacity)
{
size_t new_capacity = 2 * capacity + 1;
void *tmp = realloc(tab, new_capacity * sizeof *tab);
if (tmp == NULL)
{
perror("Failed to expand dynamic table");
break;
}
// save expanded table, and update capacity
tab = tmp;
capacity = new_capacity;
}
// notice no additional allocations here
strcpy(tab[size++], str);
}
//
// TODO: use 'tab' holding 'size' strings.
//
// then free the table
free(tab);
return 0;
}
Сводка
Исправить ваш код было довольно просто, но сделать его лучше тоже.Никогда не переставайте думать о , почему вы делаете то, что делаете, разрабатывая свои алгоритмы, и проводите много времени, разговаривая с rubber-duck .