【问题标题】:How to lowercase an entire array of strings?如何小写整个字符串数组?
【发布时间】:2021-02-20 12:51:09
【问题描述】:

在下面的函数中,我必须返回哈希表中所有重复字符串的列表,忽略参数值等于 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;
}

因此,忽略大小写意味着 strs 的每个字符串都必须变为小写。我试图通过一个动态的字符串数组来做到这一点。当所有字符串都是小写时,该函数调用另一个函数(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", "two", "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" and 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;

【问题讨论】:

  • 你不能用POSIX strcasecmp吗?
  • 另外,在比较之前不需要复制字符串...您可以手动比较小写变体 (int i = 0; while(str1[n][i] &amp;&amp; str2[n][i] &amp;&amp; tolower(str1[n][I]) == tolower(str2[n][i]) i++; if(!str1[n][i] &amp;&amp; !str2[n][i) {/* equal */;})。
  • 非常感谢!我使用了 strcasecmp() 并且它有效!

标签: arrays c string hashtable


【解决方案1】:

尝试将 32 添加到每个字符的 ASCII 值,循环是这里的朋友。 或者你可以使用内置的“toLower()”函数。

【讨论】:

  • 你的意思是 OR 每个 alphabetical 字符 (c = (c &gt;= 'A' || c &lt;= 'Z') ? (c | 32) : c)...而不是 add 到任何东西 (@ 987654322@ 不如'a' | 32 安全...对吗?
【解决方案2】:

当我尝试断言保存在列表节点中的字符串是否为 等于结果字符串(res[0] = "one" and res1 = "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() 没有足够的信息来进行释放,因为有时您使用在任何情况下都不能释放的字符串调用它。此处可能需要进行重构以使您能够正确管理内存。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    相关资源
    最近更新 更多