问题描述
在下面的函数中,我必须返回哈希表中所有重复字符串的列表,并忽略参数值等于1的情况。
upo_strings_list_t upo_find_idup(const char **strs,size_t n,int ignore_case)
{
upo_strings_list_t list = NULL;
if(ignore_case) //Must lowercase each string of strs
{
size_t i;
size_t j;
size_t size = sizeof(char);
size_t len = 0;
char *aux = malloc(sizeof(char*)); //For each string of strs to lowercase
char **aux_strs = malloc(n * sizeof(char*)); //For store lowercase strings
assert( aux != NULL );
assert( aux_strs != NULL );
for(i = 0; i < n; ++i)
{
len = strlen(strs[i]) + 1;
aux_strs[i] = malloc(len * size);
strcpy(aux,strs[i]);
for(j = 0; aux[j] != '\0'; ++j)
{
aux[j] = tolower(aux[j]);
}
strcpy(aux_strs[i],aux);
}
list = upo_find_dup((const char**)aux_strs,n);
}
else
{
list = upo_find_dup(strs,n);
}
return list;
}
因此,忽略大小写意味着str的每个字符串都必须变为小写。我试图通过动态字符串数组来做到这一点。当所有字符串都为小写时,该函数将调用另一个函数(upo_find_dup),该函数将返回重复字符串的列表(请勿重写相同的代码)。
upo_strings_list_t upo_find_dup(const char **strs,size_t n)
{
size_t i;
int val = 1;
upo_strings_list_t list = NULL;
upo_ht_linprob_t ht = upo_ht_linprob_create(UPO_HT_LINPROB_DEFAULT_CAPACITY,upo_ht_hash_str_kr2e,upo_str_cmp);
assert( ht != NULL );
for(i = 0; i < n; ++i)
{
if(upo_ht_linprob_contains(ht,&strs[i]))
{
upo_strings_list_node_t *ln = malloc(sizeof(upo_strings_list_node_t));
if(ln == NULL)
{
perror("Unable to allocate memory for a new node");
abort();
}
ln->str = (char*)strs[i];
ln->next = list;
list = ln;
}
else
{
upo_ht_linprob_put(ht,&strs[i],&val);
}
}
return list;
}
这似乎可行,因为如果我打印列表中保存的每个字符串,它们正是它们所必须的:
void test_find_idup()
{
const char *ary[] = {"One","two","four","one"};
size_t n = sizeof(ary) / sizeof(ary[0]);
//const char *res[] = {"one","two"};
upo_strings_list_t list;
list = upo_find_idup(ary,n,1);
assert( list != NULL );
//size_t i = 0;
while(list != NULL)
{
printf("%s\n",list->str);
//assert( list->str == res[i] );
list = list->next;
//++i;
}
/* PRINT: one two :OK*/
}
但是,当我尝试断言保存在列表节点中的字符串是否等于结果字符串(res [0] =“ one”和res [1] =“ two”)时,断言失败并且出现核心转储错误:
test_hashtable_linprob: test_hashtable_linprob.c:1332: test_find_idup: Assertion `list->str == res[i]' Failed.
==13842==
==13842== Process terminating with default action of signal 6 (SIGABRT)
==13842== at 0x4DEC18B: raise (raise.c:51)
==13842== by 0x4DCB858: abort (abort.c:79)
==13842== by 0x4DCB728: __assert_fail_base.cold (assert.c:92)
==13842== by 0x4DDCF35: __assert_fail (assert.c:101)
==13842== by 0x10E7E8: test_find_idup (test_hashtable_linprob.c:1332)
==13842== by 0x10EAF7: main (test_hashtable_linprob.c:1403)
==13842==
==13842== HEAP SUMMARY:
==13842== in use at exit: 901 bytes in 11 blocks
==13842== total heap usage: 234 allocs,223 frees,169,605 bytes allocated
==13842==
==13842== 13 bytes in 3 blocks are definitely lost in loss record 2 of 7
==13842== at 0x4A37ECB: malloc (vg_replace_malloc.c:307)
==13842== by 0x11029D: upo_find_idup (hashtable.c:593)
==13842== by 0x10E771: test_find_idup (test_hashtable_linprob.c:1324)
==13842== by 0x10EAF7: main (test_hashtable_linprob.c:1403)
==13842==
==13842== 424 (40 direct,384 indirect) bytes in 1 blocks are definitely lost in loss record 6 of 7
==13842== at 0x4A37ECB: malloc (vg_replace_malloc.c:307)
==13842== by 0x10F482: upo_ht_linprob_create (hashtable.c:313)
==13842== by 0x110093: upo_find_dup (hashtable.c:546)
==13842== by 0x10E66D: test_find_dup (test_hashtable_linprob.c:1310)
==13842== by 0x10EAC1: main (test_hashtable_linprob.c:1398)
==13842==
==13842== 424 (40 direct,384 indirect) bytes in 1 blocks are definitely lost in loss record 7 of 7
==13842== at 0x4A37ECB: malloc (vg_replace_malloc.c:307)
==13842== by 0x10F482: upo_ht_linprob_create (hashtable.c:313)
==13842== by 0x110093: upo_find_dup (hashtable.c:546)
==13842== by 0x11035A: upo_find_idup (hashtable.c:602)
==13842== by 0x10E771: test_find_idup (test_hashtable_linprob.c:1324)
==13842== by 0x10EAF7: main (test_hashtable_linprob.c:1403)
==13842==
==13842== LEAK SUMMARY:
==13842== definitely lost: 93 bytes in 5 blocks
==13842== indirectly lost: 768 bytes in 2 blocks
==13842== possibly lost: 0 bytes in 0 blocks
==13842== still reachable: 40 bytes in 4 blocks
==13842== suppressed: 0 bytes in 0 blocks
==13842== Reachable blocks (those to which a pointer was found) are not shown.
==13842== To see them,rerun with: --leak-check=full --show-leak-kinds=all
==13842==
==13842== For lists of detected and suppressed errors,rerun with: -s
==13842== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
Aborted (core dumped)
这也是数据结构:
/** \brief The type for nodes of list of strings. */
struct upo_strings_list_node_s {
char *str;
struct upo_strings_list_node_s *next;
};
/** \brief Alias for the type for nodes of list of strings. */
typedef struct upo_strings_list_node_s upo_strings_list_node_t;
/** \brief The type for list of strings. */
typedef upo_strings_list_node_t *upo_strings_list_t;
解决方法
尝试将32个字符添加到每个字符的ASCII值中,循环是这里的朋友。 或者,您可以使用内置的“ toLower()”函数。
,当我尝试断言保存在列表节点中的字符串是否为 等于结果字符串(res [0] =“ one”和res {1 =“ two”), 断言失败并出现核心转储错误
仅当您倾向于将转储加载到调试器中以检查程序中止时的内存状态时,才产生核心转储。很少有人这样做,而且配置系统以使根本不产生核心转储的情况并不少见。在此答案中,我将不再关注它。
您对assert()
的许多使用都是不合适的。断言用于对代码的正确性进行运行时测试。它们对于测试和记录您的代码关于代码的其他部分将如何使用它的假设,或关于代码依赖于编译器产生的特性很有用。 断言绝不能包含每次执行程序都需要运行的代码,例如成功分配内存的测试,因为取决于编译选项,可执行文件可能会完全忽略它们。如果您的一个断言失败,则始终意味着您的代码有错误(可能是断言本身)。
如果您想要类似的功能来依赖于输入,运行时环境或其他可能随程序运行而变化的行为,请编写自己的abort_unless()
函数或宏。
接下来,看来您实际上是在谈论此断言,该断言在实际发布的代码中已注释掉:
//assert( list->str == res[i] );
该断言中的测试与您的文本中的一个测试有重要区别,但我将重点介绍代码中的一个。可能assert
的特定用法是一种适当的用法,因此,如果失败,则代码错误如何?这是有问题的,因为==
运算符正在比较两个char
指针本身,而不是它们指向的数据,并且没有理由确定两个指针将相等。您似乎想雇用strcmp()
,而不是:
assert(strcmp(list->str,res[i]) == 0);
此外,此代码在upo_find_idup()
中...
char *aux = malloc(sizeof(char*)); //For each string of strs to lowercase
...为指针本身分配足够的空间,可能不超过8个字节。如果您只想存储一个指针,则不需要动态分配或额外的间接层,但实际上是在存储字符串 contents 。如果您的任何字符串长于指针,这将超出分配空间的范围。
更糟糕的是,您使用aux
会引入不必要的额外工作和代码。可以为每种情况分配足够长的字符串,但是您已经在以每种aux_strs[i]
的形式这样做。只需直接操作它们即可。
此外,为aux_strs
分配的内存本身已泄漏,为任何未传递到生成的链表的成员分配的内存也已泄漏。但这对您来说也是一个后勤问题,因为您必须注意避免释放被携带到链表中的成员。此外,upo_find_dup()
没有足够的信息来进行释放,因为有时您用字符串调用它,无论如何它都不能释放。此处可能需要进行重构,以使您能够正确管理内存。