【问题标题】:Const array of arrays as function argumentconst 数组数组作为函数参数
【发布时间】:2021-09-09 12:52:37
【问题描述】:

我不太明白如何正确排列 const 以便将数组的常量数组传递给函数,例如字符串数组:

void f (char **strings);

int main (void)
{
    char strings[][2] = { "a", "b", "c" };
    f (strings);
}

你能告诉我把const放在哪里吗?据我了解,应该有两个const,上面示例中的一个应该位于char之前。

重复的可能性很大,但是我找不到类似的问题:(

【问题讨论】:

  • 数组衰减为指向其第一个元素的指针,但是这种衰减不是递归的。因此,数组数组衰减为指向 arrays 的指针,而不是指向指针的指针。在您的情况下,strings 将衰减为 char (*)[2]
  • 至于const的放置位置,您必须记住,指针指向的数据可以是const,在您的情况下将是字符数组。所以要添加const,它将是char (const *)[2]
  • 您可以使用const char *strings[] = { "a", "b", "c" }; 使其与void f (const char **strings);char strings[][2] = { "a", "b", "c" };void f (char (*strings)[2]); 一起使用。
  • 或者你可以让 pointer 保持不变,在这种情况下它会是char (* const)[2],我猜这就是你真正想要的?
  • @Someprogrammerdude: char (const *)[2] 不是正确的类型名称或声明。 char (* const)[2] 将是一个 const 指针,指向 2 个数组 const char

标签: arrays c string constants


【解决方案1】:

首先,声明并不理想。 char strings[][2] 声明了不确定数量的 char[2] 数组,其中数量由初始化程序确定。在大多数情况下,声明一个指针数组更有意义,因为这意味着指向的字符串不需要具有一定的固定长度。

因此您可以将声明更改为const char* strings[3] = { "a", "b", "c" };。当然,除非意图是允许 1 个字符和 2 个空终止符的字符串,否则原始代码是正确的。如果你需要读/写字符串,那么我们也不能使用指针表示法。

您可以通过将const char* strings[3] 声明为函数来传递该函数

void f (const char* strings[3]);

就像你声明你传递给函数的数组一样。

现在,当函数声明的一部分“衰减”为指向第一个元素的指针时,数组会发生这种情况。在这种情况下,指向 const char* 项目的指针,写为 const char**
所以你可以写void f (const char** strings);,它会是等价的。

【讨论】:

  • @user694733 糟糕,已修复。谢谢。
【解决方案2】:

我认为this resource 解释得很好。一般来说,这取决于您需要的 const 保护的“深度”。如果您希望函数“f”对“外部”指针、它指向的指针(“内部”指针)和“内部”指针指向的字符都具有只读访问权限,则使用

const char *const *const strings

如果您想放松警卫以使其合法化:

strings = NULL;

然后使用:

const char *const *strings

进一步放松,以允许:

strings = NULL;

*strings = NULL;

只使用一个“const”:

const char **strings

【讨论】:

    【解决方案3】:

    了解数组数组(例如,由 2 个字符组成的数组)和指针数组之间的区别很重要。正如措辞所暗示的,它们的元素类型完全不同:

    • 数组数组中的每个元素,例如下面的my_arr_of_arrays,都是一个数组!不是地址,也不是指针:每个元素都是一个适当的数组,每个元素的大小相同(她:2),连续固定数量的子元素。 数据就在数组对象中。char my_arr_of_arrays[][2] = { "a", "b", "c", "" }; 之后,my_arr_of_arrays 是一系列字符,成对分组:'a'、'\0'、'b'、'\ 0'、'c'、'\0'、'\0'、'\0'。下图说明了这一点。 my_arr_of_arrays 中的每个元素的大小为 2 个字节。 每个字符串字面量用于复制其中的字符到my_arr_of_arrays对应的数组元素中。数据可以稍后覆盖,复制不是const。 p>

    • 将此与指针数组进行对比,例如下面的my_arr_of_ptrs!这样一个数组中的每个元素都是一个指针。 正确的数据在其他地方! 实际数据可能是用 malloc 分配的,或者是静态数据,如我下面示例中的字符串文字。每个元素(每个地址)在 32 位架构上的大小为 4 字节,在 64 位架构上为 8 字节。 不会从字符串文字中复制任何内容: 指针只是指向程序中存储文字本身的位置。数据是常量,不能被覆盖。

    令人困惑的是,这些完全不同的数据结构可以用相同的花括号初始化列表进行初始化;令人困惑的是,字符串文字可以用作将字符复制到数组中的数据源,或者可以获取它们的地址并将其分配给指针:char arr[3] = "12":char *ptr = "12"; 都是有效的,但对于 arr a复制并为ptr 获取字符串文字本身的地址

    您的程序显示 C 允许您将 2 个字符的数组的地址传递给需要指针地址的函数;但如果函数试图取消引用一个“地址”,实际上是一个字符序列,这是错误的并且会导致灾难。 C++ 禁止这种无意义的转换。

    以下程序和图像可能会阐明两个不同数组的数据布局。

    #include <stdio.h>
    
    void f_array_of_arrays(char(* const arr_of_arrays)[2])
    {
        for (int i = 0; arr_of_arrays[i][0] != 0; i++)
        {
            printf("string no. %d is ->%s<-\n", i, arr_of_arrays[i]);
        }
    
        const char myOtherArr[][2] = { "1", "2", "3", "4", "" };
        // arr2d = myOtherArr; //  <-- illegal: "const arr2d"!
        arr_of_arrays[0][0] = 'x';     // <-- OK: The chars themselves are not const.
    }
    
    void f_array_of_pointers(const char** arr_of_ptrs)
    {
        for (int i = 0; arr_of_ptrs[i][0] != 0; i++)
        {
            printf("string no. %d is ->%s<-\n", i, arr_of_ptrs[i]);
        }
        arr_of_ptrs[1] = "87687686";
        for (int i = 0; arr_of_ptrs[i][0] != 0; i++)
        {
            printf("after altering: string no. %d is ->%s<-\n", i, arr_of_ptrs[i]);
        }
    }
    
    int main()
    {
        char my_arr_of_arrays[][2] = { "a", "b", "c", "\0" };  // last element has two zero bytes.
        const char* my_arr_of_ptrs[] = { "111", "22", "33333", "" }; // "jagged array"
    
        f_array_of_arrays(my_arr_of_arrays);
        f_array_of_pointers(my_arr_of_ptrs);
    
        // disaster: function thinks elements are arrays of char but
        // they are addresses; does not compile as C++
        // f_array_of_arrays(my_arr_of_ptrs); 
    
        // disaster: function thinks elements contain addresses and are 4 bytes,
        // but they are arbitrary characters and 2 bytes long; does not compile as C++
        // f_array_of_pointers(my_arr_of_arrays);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-29
      • 2012-07-22
      • 2012-11-24
      • 2011-02-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多