【问题标题】:unable to return string无法返回字符串
【发布时间】:2021-10-22 14:32:28
【问题描述】:

输出应该只返回字符串,在字符串中只保留 2 个相同的字母。

示例输入:aaaabbbbaaaa
输出:aabbaa
在这段代码中,我无法在 C 中返回重新创建的字符串。

#include <stdio.h>
#include <string.h>

char *solve(char *s) {
    char str[10];
    int x = strlen(s);
    int j = 0;
    for (int i = 0; i < x; i++) {
        if (s[i] != s[i + 1]) {
            str[j] = s[i];
            j++;
            continue;
        }
        if (s[i] == s[i + 2]) {
            str[j] = s[i];
            j++;
            i++;
        }
    }
    return str;
}

int main() {
   int t = 1, count = 1;
   while (t >= count) {
       char arr[10] = "aaabaaaa";
       printf("Case #%d: %s\n", count, solve(arr));
       count++;
   }
}

【问题讨论】:

  • 您不能返回指向局部变量的指针。 solve 返回后,str 不复存在,所以它的地址没有意义。
  • 话虽如此,您必须意识到,与其他语言不同,C 中没有真正的字符串类型。阅读 C 教科书中处理字符串的章节。
  • 编译时,始终启用警告,然后修复这些警告。 (对于gcc,最少使用:-Wall -Wextra -Wconversion -pedantic -std=gnu11)注意:其他编译器使用不同的选项来产生相同的结果

标签: c string return


【解决方案1】:

为了完整起见,这是另一种解决方案。这个:

  • 在函数内部分配内存。
    可以说,这是最好的地方,因为只有这个函数知道结果将占用多少内存。更高级的实现可以,例如,使用realloc 或首先扫描输入以确定输出字符串的长度。
  • 是一种更通用的解决方案,能够通过更改一个常数来更改允许的重复次数。
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static char *solve(char const * restrict s)
{
    unsigned const numberOfEqualCharsMax = 2U;

    // The output string will be maximally as large as the input string
    size_t sSize = strlen(s);
    char *str = (char*) malloc(sSize + 1U); // +1 for the '\0'
    if (!str)
        return NULL;

    str[0] = s[0]; // Either copy the first char, or '\0'

    // Handle the empty string. Already copied '\0', now return
    if (sSize == 0)
        return str;

    // Handle |sSize| > 0
    size_t idxOut = 1U;
    unsigned numberOfEqualChars = 1U;
    for (size_t idx = 1U; idx < sSize; ++idx)
    {
        if (s[idx - 1] == s[idx])
            ++numberOfEqualChars;
        else
            numberOfEqualChars = 1U;

        if (numberOfEqualChars <= numberOfEqualCharsMax)
            str[idxOut++] = s[idx];
    }

    str[idxOut] = '\0';
    return str;
}

int main(void)
{
   char arr[] = "ababaabbaaabbbabbaaba";
   char *solution = solve(arr);
   if (!solution)
   {
       printf("Memory allocation failed\n");
       return EXIT_FAILURE;
   }

   printf("%s\n", solution);
   free(solution);
}

请注意,现在main 必须决定如何处理由solve 分配的失败。

【讨论】:

    【解决方案2】:

    返回指向使用自动存储在本地定义的对象的指针(例如solve() 中的str)具有未定义的行为,因为该对象在函数返回时不再可访问。

    有多种方法可以根据您的目的解决此问题:

    • 您可以就地修改字符串,假设它是可修改的。
    • 你可以用malloc()分配一个新的字符串,在里面构造修改后的字符串并返回指针。
    • 可以将指向目标数组的指针传递给solve(),以便将修改后的字符串构造成。

    对于第二个和第三个选项,目标数组必须足够大,并且对于所有选项,修改后的字符串必须正确以空结尾,这是您代码中的另一个问题。

    这是一个修改版本,使用 2 指方法修改字符串的简单方法:使用不同的索引读取和写入 char 数组,除了第二次测试和缺少的空终止符。

    #include <stdio.h>
    #include <string.h>
    
    char *solve(char *s) {
        size_t i, j;
        for (i = j = 0; s[i]; i++) {
            if (s[i] != s[i + 1] || s[i] != s[i + 2]) {
                s[j++] = s[i];
            }
        }
        /* set the null terminator: necessary if the string was shortened. */
        s[j] = '\0';
        return s;
    }
    
    int main() {
        const char *tests[] = {
            "",
            "a",
            "aa",
            "aaa",
            "aaab",
            "aaabb",
            "aaabbb",
            "aaabaaaa",
            "aaaabbbbaaaa",
            "ababababa",
        };
        int i, n = sizeof(tests) / sizeof(tests[0]);
        for (i = 0; i < n; i++) {
            char arr[20];
            strcpy(arr, tests[i]);
            printf("Case #%d: \"%s\" -> ", i + 1, arr);
            printf("\"%s\"\n", solve(arr));
        }
        return 0;
    }
    

    输出:

    Case #1: "" -> ""
    Case #2: "a" -> "a"
    Case #3: "aa" -> "aa"
    Case #4: "aaa" -> "aa"
    Case #5: "aaab" -> "aab"
    Case #6: "aaabb" -> "aabb"
    Case #7: "aaabbb" -> "aabb"
    Case #8: "aaabaaaa" -> "aabaa"
    Case #9: "aaaabbbbaaaa" -> "aabbaa"
    Case #10: "ababababa" -> "ababababa"
    

    【讨论】:

      【解决方案3】:

      您不能返回指向局部变量的指针。 solve 返回后,str 不复存在,所以它的地址没有意义。您要么在堆上分配它(例如通过malloc),要么从main 传递存储。例如:

      void solve(const char *s, char *str){
      ...    
      }
      int main(void)
      {
         int t=1, count = 1 ;
         while (t>=count){
              char arr[10] = "aaabaaaa";
              char ret[sizeof arr];
              solve(arr, ret);
              printf("Case #%d: %s\n",count, ret));
              count++;
         }
      }
      

      您当前的代码似乎没有向str 添加空终止符。确保使用str[x] = '\0' 添加它,并确保不要将s[i] 引用为i &gt;= sizeof s。对于 i >= 8,s[i+2] 可能是一个问题(例如,将导致未定义的行为)。

      还要注意,在这种情况下,“解决方案”似乎很有可能被写回到原始字符串中(您可以“就地”解决这个问题),所以根本不需要额外的缓冲区.

      【讨论】:

        【解决方案4】:

        您遇到问题的一个主要原因是您试图返回一个指向在堆栈上分配的变量的指针。

        当您在函数中定义局部变量并且该变量未标记为static 时,典型的策略是将该值分配到堆栈上。当您返回按值传递的东西(如整数)时,这没什么大不了的,但是当您返回一个指针时,这实际上是 str char[10] 是什么,您现在正在返回指向某物的指针的值在堆栈上。

        应该假定该值是不安全的,因为它几乎肯定会在返回后不久被覆盖,甚至可能在变量超出范围后立即被覆盖。

        您最好传入第二个指针,该指针指向父函数分配的内存并将结果字符串复制到那里。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-23
          • 2014-06-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-02
          • 2021-09-03
          • 2020-03-18
          相关资源
          最近更新 更多