【问题标题】:Building char array from a string (C)从字符串构建 char 数组 (C)
【发布时间】:2016-01-21 04:24:52
【问题描述】:

我正在用 C 语言编写一个简单的函数,它应该从字符串“abc”构建一个 char 数组——因此它应该构建 {'a','b','c'}——并返回一个指向该数组的指针。这是我的这个函数的代码:

char * makeArr()
{
    static char arr[3];

    sprintf(arr, "%s\n", "abc");

    return arr;
}

当我在 main 中调用此方法时出现问题:

int main(int argc, char *argv[])
{
    char *arr[3];

    arr = makeArr();

    return 0;
}

编译器抱怨类型转换/冲突。我已经玩了很长一段时间的指针,强制转换和取消引用,但似乎无法让它工作。请让我知道我的逻辑哪里错了。

【问题讨论】:

  • char *arr[3] 是一个包含三个 char * 的数组。 makeArr 返回一个 char *,而不是其中三个的数组。顺便说一句,"abc\n" 有四个字符长,五个带有空终止符,因此您不应该尝试将其写入大小为 3 的缓冲区。
  • @hobbs 更新了我的缓冲区大小以拥有足够的空间。
  • 你忘记了sprintf(arr, "%s\n", "abc")后面的分号。
  • 这段代码在很多层面上都是错误的......
  • 从函数返回指向堆栈分配内存的指针是未定义的行为。您需要传入指针或动态分配空间。

标签: c arrays function pointers types


【解决方案1】:

嗯……这段代码中有几个错误。让我们从编译器抱怨的最明显的问题开始:

char *arr[3];

这行声明arr 是一个由三个指针 指向char 的数组。您从函数返回的是指向 char 的单个指针 -> 不匹配。

下一步:

static char arr[3];
sprintf(arr, "%s\n", "abc")

在这里您保留 3 个chars。 sprintf() 将写入 5 chars。 %s字符串文字 "abc" 中的 3 个字符替换。您添加一个换行符,然后添加一个0 作为“字符串”结尾的标记。使 5。顺便说一句,这是 未定义的行为。你写到数组的末尾。像这样的代码可以编译,但根本无法保证运行时会发生什么。


在这里进行剪辑。您应该阅读 C 中的数组和指针。如果您正在阅读的文本声称它们是相同的……就停在那里并找到更好的文本。他们不是。

这里我尽量简单解释一下,适合Q&A风格。

C 中的数组确实是多个值的连续空间。 char arr[3] 表示一个包含 3 个chars 的变量。

另一方面,char * 只是一个指向char 的指针——这可能是数组的第一个元素。

在 C 中,不能将数组作为函数参数传递,也不能从函数返回数组。尝试这样做会导致隐式转换:实际传递的 is 是指向该数组第一个元素的指针。

我认为缺少的最后一点信息是 C 中的 字符串文字 是什么:它是一个数组(匿名,例如,它没有名称),包含双精度中的所有字符引号加上一个0附加。 0 标志着 C 中“字符串”的结束。

在表达式中,字符串字面量的计算结果是指向第一个元素的指针。

所以,是这样的:

char *foo = "bar";

会导致foo指向数组的b。就像写作一样

static const char no_name_0[] = { 'b', 'a', 'r', 0 };
char *foo = &(no_name_0[0]);

【讨论】:

    【解决方案2】:

    您无法将 makeArr 的结果分配给 arr。我想这是你的铸造错误。过于简单化, arr 指向堆栈中分配 10 个字符的数组的位置。所以,我会将 arr 作为 char* 传递给 makeArr。所以,你最终会得到这样的结果:

    #include <stdio.h>
    char * makeArr(char *arr)
    {
        sprintf(arr, "%s\n", "abc");
        return arr;
    }
    
    int main(int argc, char *argv[])
    {
        char arr[10];
    
        makeArr(arr);
        printf("%s\n", arr);
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      将数组作为参数传递并在被调用函数中修改它,会更容易。如果您是静态创建数组并且不需要分配内存,请不要,只需将指针传递给要通过引用修改的函数

      void makeArr(char arr[]){
          sprintf(arr, "%s\n", "abc");
      }
      

      只需将现有声明的数组传递给 makeArr 函数...

      int main(int argc, char *argv[]) {
        char arr[10];
        makeArr(arr);
        return 0;
      }
      

      【讨论】:

        【解决方案4】:

        首先,char arr[3]; 太小,无法存储 "abc\n"。它必须至少有 5 个元素,包括终止空字符。

        那么,char *arr[3];char* 的三元素数组。
        你应该把makeArr()的返回值(它有char*类型)赋值给arr[0]或者其他元素,或者你应该把main函数中arr的类型改成char*,也一样键入makeArr() 的返回值。

        此外,这个makeArr() 不创建任何数组并返回(指向)现有数组的指针。 Yoy 应该使用malloc() 来“制作一个数组”。

        更新:

        在 C 中将值 char* 分配给数组 char arr[10]; 似乎无效。 您应该使用strcpy()strncpy()(比strcpy() 更安全)在数组之间复制存储在数组中的字符串。

        【讨论】:

        • 将缓冲区大小更新为 10
        【解决方案5】:

        除其他外,您感到困惑:

        char arr[3]; // array of 3 chars.

        和,

        char *arr[3]; // array of 3 pointers to char.

        在main()中,你应该只写char *arr;

        【讨论】:

          猜你喜欢
          • 2014-03-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-06-15
          相关资源
          最近更新 更多