我是C中的新手,为了了解结构我正在构建一个为 struct ll_string 提供一组有限功能的程序,它基本上是一个链表字符串。
我试图实现的一组函数包括一个 insert_ll_string()函数,它应该将传入的 struct ll_string 元素汇总到另一个元素的末尾< em> struct ll_string 元素但是没有这样做,因为在我的测试用例中调用函数的那一刻,程序崩溃了一个sig错误。这是 test_insert()函数的 STILL WORKS 和 SIG FAULT 注释。
这是它的头文件:
file: ll_string.h
struct ll_string {
char *string;
struct ll_string *next;
};
struct ll_string *create_ll_string(char *, struct ll_string *);
void insert_ll_string(struct ll_string *, struct ll_string *);
void remove_item_from_ll_string(struct ll_string *, struct ll_string *);
void free_ll_string(struct ll_string *);
void print_ll_string(struct ll_string *);
这就是它相应的 .c 文件缺少 ll_string.h 中声明的函数的一些定义,但我猜我的问题可能只围绕着无论如何,函数 create_ll_string()和 insert_ll_string()。
file: ll_string.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ll_string.h"
/* create_ll_string: allocates memory for a new struct ll_string and
* initializes it with given arguments returns a pointer to new struct */
struct ll_string *create_ll_string(char *string, struct ll_string *next) {
struct ll_string *new_ll_string;
if (!string) {
printf("string can\'t be NULL\n");
return NULL;
}
if (*string == '\0') {
printf("string needs to be at least 1 char long\n");
return NULL;
}
if (!(new_ll_string = (struct ll_string *) malloc(sizeof(struct ll_string)))) {
printf("couldn\'t allocate mem for new ll_string\n");
exit(EXIT_FAILURE);
}
new_ll_string->string = strdup(string);
new_ll_string->next = next;
return new_ll_string;
}
/* insert_ll_string: concanates item to the end of dest */
void insert_ll_string(struct ll_string *dest, struct ll_string *item) {
struct ll_string *cur;
if (!dest) {
printf("dest and item can\'t be NULL\n");
return;
}
if (!item) {
printf("item can\'t be NULL\n");
return;
}
cur = dest;
while (!cur->next) {
cur = cur->next;
}
cur->next = item;
return ;
}
/* remove_item_from_ll_string: removes item from list src */
void remove_item_from_ll_string(struct ll_string *src, struct ll_string *item) {
return ;
}
/* printf_ll_string: prints each string in ll_string */
void print_ll_string(struct ll_string *ll_string) {
if (!ll_string) {
printf("ll_string is NULL\n");
return ;
}
do {
printf("%s\n", ll_string->string);
} while (!(ll_string = ll_string->next));
}
/* free_ll_string: frees all memory pointed to by ll_string */
void free_ll_string(struct ll_string *ll_string) {
struct ll_string *next;
if (!ll_string) {
return ;
}
while ((next = ll_string->next)) {
free(ll_string->string);
free(ll_string);
ll_string = next;
}
}
这是我的测试。一切正常,直到 test_insert()函数引发 insert_ll_struct()。 ( test_create()按预期工作)使用MinUnit框架进行测试。
file: tests_ll_string.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "minunit.h"
#include "ll_string.h"
#define MAX_ERROR_MSG_LENGTH 1000
int tests_run = 0;
static char *test_create(void) {
struct ll_string *test_ll;
struct ll_string *test_null_ll;
char *empty_string = strdup("");
char *null_string = NULL;
char *correct_string = strdup("this should work");
char *correct_string2 = strdup("this should also work");
char *error_msg;
if (!(error_msg = (char *) malloc(sizeof(char) * MAX_ERROR_MSG_LENGTH))) {
printf("couldn\'t allocate mem for error msg");
exit(EXIT_FAILURE);
}
// test_ll->string == correct_string
// test_ll->next == NULL
test_ll = create_ll_string(correct_string, NULL);
sprintf(error_msg, "error, test_ll->string != \"%s\" is %s", correct_string, test_ll->string);
mu_assert(
error_msg,
strcmp(test_ll->string, correct_string) == 0);
// test_ll->next->string == correct_string
// test_ll->string == correct_string2
test_ll = create_ll_string(correct_string2, test_ll);
sprintf(error_msg, "error, test_ll->string != \"%s\" is %s", correct_string2, test_ll->string);
mu_assert(
error_msg,
strcmp(test_ll->string, correct_string2) == 0);
sprintf(error_msg, "error, test_ll->next->string != \"%s\" is \"%s\"", correct_string, test_ll->next->string);
mu_assert(
error_msg,
strcmp(test_ll->next->string, correct_string) == 0);
test_null_ll = test_ll;
test_null_ll = create_ll_string(empty_string, test_ll);
// test_null_ll == NULL
mu_assert(
"error, test_null_ll != NULL",
test_null_ll == NULL);
test_null_ll = test_ll;
test_null_ll = create_ll_string(null_string, test_ll);
// test_null_ll == NULL
mu_assert(
"error, test_null_ll != NULL",
test_null_ll == NULL);
sprintf(error_msg, "error, test_ll->string != \"%s\" is \"%s\"", correct_string2, test_ll->string);
mu_assert(
error_msg,
strcmp(test_ll->string, correct_string2) == 0);
sprintf(error_msg, "error, test_ll->next->string != \"%s\" is \"%s\"", correct_string, test_ll->next->string);
mu_assert(
error_msg,
strcmp(test_ll->next->string, correct_string) == 0);
free_ll_string(test_ll);
free(correct_string);
free(correct_string2);
free(empty_string);
free(error_msg);
return 0;
}
static char *test_insert(void) {
struct ll_string *ll_test1;
struct ll_string *ll_test2;
struct ll_string *ll_test3;
char *test_string1 = strdup("test_string1");
char *test_string2 = strdup("test_string2");
char *test_string3 = strdup("test_string3");
char *error_msg;
if (!(error_msg = (char *) malloc(sizeof(char) * MAX_ERROR_MSG_LENGTH))) {
printf("couldn\'t allocate mem for error msg");
exit(EXIT_FAILURE);
}
ll_test1 = create_ll_string(test_string1, NULL);
ll_test2 = create_ll_string(test_string2, NULL);
ll_test3 = create_ll_string(test_string3, NULL);
// STILL WORKS
insert_ll_string(ll_test1, ll_test2); // SEG FAULT
insert_ll_string(ll_test1, ll_test3);
sprintf(error_msg, "error, ll_test1->string != \"%s\" is \"%s\"", test_string1, ll_test1->string);
mu_assert(
error_msg,
strcmp(ll_test1->string, test_string1) == 0);
sprintf(error_msg, "error, ll_test1->next->string != \"%s\" is \"%s\"", test_string2, ll_test1->next->string);
mu_assert(
error_msg,
strcmp(ll_test1->next->string, test_string2) == 0);
sprintf(error_msg, "error, ll_test1->next->next->string != \"%s\" is \"%s\"", test_string1, ll_test1->next->next->string);
mu_assert(
error_msg,
strcmp(ll_test1->next->next->string, test_string3) == 0);
free_ll_string(ll_test1);
free_ll_string(ll_test2);
free_ll_string(ll_test3);
free(test_string1);
free(test_string2);
free(test_string3);
return 0;
}
static char *all_tests(void) {
mu_run_test(test_create);
mu_run_test(test_insert);
return 0;
}
int main(int argc, char* argv[]) {
char *result = all_tests();
if (result != 0) {
printf("%s\n", result);
} else {
printf("ALL TESTS PASSED\n");
}
printf("Tests run: %d\n", tests_run);
return result != 0;
}
这是编译和执行的输出:
>> gcc -Wall -o test ll_string.c tests_ll_string.c
>> ./test
string needs to be at least 1 char long
string can't be NULL
[1] 6789 segmentation fault (core dumped) ./test
导致此Sigmentation错误的原因是什么?我没有在程序崩溃的部分中访问除局部变量之外的任何内存。我没有解除引用我传递给 insert_ll_struct()的指针,至少在引发函数后不立即。
提前感谢您的帮助
答案 0 :(得分:1)
我认为答案正在盯着我们。在insert_ll_string()
:
while (!cur->next) {
应该是
while (cur->next) {
答案 1 :(得分:0)
我要查看free_ll_string()
中的逻辑。你确定你没有两次释放记忆吗?在代码中看起来如果释放链中的所有字符串。因此,我认为您将test_ll
多次免费test_create
。看看你在禁用test_create
时是否仍然收到错误,如果没有,那么你发现我认为可能是由于未定义的行为造成的,因为你不止一次地释放东西......
最好在释放指向的内存后将任何释放的指针设置为NULL,然后你就可以避免这个问题了。
/* free_ll_string: frees all memory pointed to by ll_string */
void free_ll_string(struct ll_string *ll_string) {
struct ll_string *next;
if (!ll_string) {
return ;
}
while ((next = ll_string->next)) {
free(ll_string->string);
free(ll_string);
ll_string = next;
}
}
答案 2 :(得分:0)
while(!cur-&gt; next){cur = cur-&gt; next; } 这段代码会导致崩溃,假设cur-&gt;下一次返回null,而不是你试图接受null,那么你应该把mm检查为cur in while循环,就像thiswhile一样(null!= cur&amp;&amp;!cur-&gt; next )