Вы не проверяете, нашел ли strtok
все токены. Вы должны проверить указатель, возвращенный strtok()
перед его использованием. Если вы этого не сделаете, неверный ввод вызовет неопределенное поведение.
В вашем случае длина ввода превышает 682 байта, первые 681 байт считываются в массив, и этот фрагмент не содержит достаточно токенов, что делает один из вызовов strtok()
для возврата NULL
, вызывая неопределенное поведение когда вы разыменовываете этот нулевой указатель с помощью strlen()
.
Всегда проверяйте и сообщайте об ошибках, вы сэкономите бесчисленные часы отладки.
Когда происходит сбой программы, утечки памяти, о которых сообщает valgrind, не имеют смысла, поскольку программа не завершила свое нормальное выполнение и, конечно, не освободила выделенную память должным образом. Память все еще возвращается в операционную систему после завершения программы, но valgrind сообщает о не освобожденных блоках, вызывая free()
.
Чтобы избежать произвольного ограничения длины строки, вы можете использовать стандартную функцию POSIX getline()
, которая перераспределяет массив по мере необходимости.
Вы также должны использовать strdup
для выделения копий строк в одном вызове функции:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct words {
char *word1;
char *word2;
char *word3;
} words;
typedef struct node{
words cont;
struct node *next;
} node;
typedef node *link; // hiding pointers behind typedefs is not recommended
link head;
link add(char c[]) {
words x = { NULL, NULL, NULL };
char *str;
link temp;
if (strtok(c, " ") != NULL
&& (str = strtok(NULL, " ")) != NULL
&& (x.word1 = strdup(str)) != NULL
&& (str = strtok(NULL, " ")) != NULL
&& (x.word2 = strdup(str)) != NULL
&& (str = strtok(NULL, "")) != NULL
&& (x.word3 = strdup(str)) != NULL
&& (temp = malloc(sizeof(*temp)) != NULL) {
temp->cont = x;
temp->next = head;
return head = temp;
} else {
free(x.word3);
free(x.word2);
free(x.word1);
return NULL;
}
}
int main() {
char *input = NULL;
size_t input_size = 0;
head = NULL;
while (getline(&input, &input_size, stdin) >= 0 && *input != 'x') {
input[strcspn(input, "\r\n")] = '\0';
if (*input == 'a')
add(input);
...
}
...
}
free(input);
...
return 0;
}