【问题标题】:Confusion between "int array[int]" and "int *array"“int array[int]”和“int *array”之间的混淆
【发布时间】:2019-06-18 02:58:43
【问题描述】:
int array[100];

int *array;

我对@9​​87654323@ 和int *array 之间的区别感到困惑。

基本上,当我执行int array[100]100 这只是int 的一个示例)时,我只是在内存中保留了 100 个整数的空间,但我可以执行int * array 并且我没有指定任何这个数组的大小类型,但我仍然可以做array[9999] = 30,这仍然有意义。

那么这两者有什么区别呢?

【问题讨论】:

  • “我没有为这个数组指定任何类型的大小” 你必须这样做,通常会按照int *array = malloc(sizeof(int)*10000) 的方式做一些事情,这里是10000是大小。如果您不使指针指向有效内存,则 array[9999]=30; 是未定义的行为,可能会使您的程序崩溃或导致其他错误/不可预测的结果。
  • 对于初学者,int *array 必须手动进行 malloc() 编辑。
  • 哦,非常感谢
  • 我建议c-faq的第4、5、6和7节。
  • @JoaoParente:您可以通过单击分数下方的灰色复选标记来接受其中一个答案。

标签: c arrays pointers memory-management


【解决方案1】:

如果没有在int * array 中指定大小,array[9999] = 30 可能会导致分段错误,因为它可能导致访问无法访问的内存

基本上int * array 指向一个随机位置。要访问第 9999 个元素,array 必须指向具有足够空间的位置。但声明 int * array 并没有明确为此创建任何空间。

【讨论】:

    【解决方案2】:

    int array[100]; 定义了一个int数组

    int *array; 定义了一个指向int指针。该指针可能指向int 变量或int 数组的元素,或者根本不指向任何内容(NULL),甚至指向内存中的任意、有效或无效地址,就是这种情况当它是一个未初始化的局部变量时。将此指针称为array 有点误导,但通常在命名确实指向实际数组的函数参数时使用。编译器无法根据指针值确定数组的大小(如果有)。

    这是一个地形隐喻:

    • 将数组想象成一条有建筑物的街道。它具有 GPS 坐标(内存地址)、名称(但并非总是如此)和固定数量的建筑物(在给定时间,很难更改)。街道名称与建筑物编号一起指定了精确的建筑物。如果您指定的数字大于最后一个数字,则它是无效地址。

    • 指针是一个非常不同的东西:把它想象成一个地址标签。这是一张可以用来识别建筑物的小纸片。如果它是空白的(一个空指针),它是没有用的,如果你把它粘在一个字母上并发送,这个字母会丢失并被丢弃(未定义的行为,但很容易判断它是无效的)。如果您在其上写入无效地址,效果类似,但在交付失败之前可能会花费更多(未定义的行为且难以测试)。

    • 如果一条街道被夷为平地(如果内存被释放),以前写的地址标签不会被修改,但它们不再指向任何有用的东西(如果您发送信件,则为未定义的行为,困难的那种)。如果稍后以标签上的名称命名一条新街道,则该字母可能会送达,但可能不是预期的那样(再次出现未定义的行为,内存被释放并且其他一些分配的对象恰好位于相同的内存地址)。

    • 如果您将建筑物传递到功能,您通常不会挖掘它并用卡车运送它,而只是传递它的街道地址(指向街道的第 n 个建筑物的指针,&array[n])。如果不指定建筑物而只命名街道,则表示去街道的开头。类似地,当将数组传递给函数是 C 时,函数接收到指向数组开头的指针,我们说 arrays 作为指针衰减

    【讨论】:

      【解决方案3】:

      指针是一个指针,它指向别的地方(比如数组的第一个元素)。编译器没有关于它可能指向的位置或它可能指向的数据大小的任何信息。

      数组是由多个相同类型的连续元素组成的数组。编译器知道它的大小,因为它总是被指定(尽管有时只是隐式指定大小)。

      一个数组可以被初始化,但不能被赋值。数组也经常衰减为指向其第一个元素的指针。

      数组衰减示例:

      int array[10];
      
      int *pointer = array;  // Here the symbol array decays to the expression &array[0]
      
      // Now the variable pointer is pointing to the first element of array
      

      数组不能自然地传递给函数。当您声明像int arr[] 这样的函数参数时,编译器会将其翻译为int *arr

      所有这些信息以及更多信息都应该包含在任何一本好书、教程或课程中。

      【讨论】:

      • 编译器并不总是知道数组的大小。例如,extern int array[]; 声明了一个在不同 mdule 中或稍后在同一模块中定义的数组。大小未知,sizeof(array) 应该会产生错误。
      【解决方案4】:

      您会发现一些有用的知识点:

      • 通过int arr[N] 指定int 类型的数组,可以存储N 整数。要获取有关内存阵列占用量的信息,您可以使用 sizeof 运算符。只需将数组中的项目数乘以类型的大小即可:N*sizeof(int)
      • 数组的名称指向数组中的第一个元素,例如*arrarr[0] 一样,你可能想知道为什么a[5] == 5[a]
      • 未初始化的非静态存储持续时间数组填充了不确定的值。
      • 数组的大小可能在运行时已知,如果您编写int arr[] = {1, 2},则该大小由编译器计算。
      • 访问不存在的元素会导致未定义的行为,这意味着任何事情都可能发生,并且在大多数情况下您会得到垃圾值。

      • 通过int *array 指定指针 array int 类型
      • 除非分配了值,否则默认情况下指针将指向某个垃圾地址。
      • 如果您根本不分配内存或未完全分配内存或访问不存在的元素但尝试将指针用作数组,您将获得预期的未定义行为。
      • 分配内存后(不再需要指针时)应释放内存。

      【讨论】:

        【解决方案5】:

        非技术性解释:

        指针的内容指的是地址(可能有效也可能无效)。一个数组一个地址(它必须是有效的数组才能存在)。

        你可以把指针想象成一个信封——你可以在上面放任何你想要的地址,但是如果你想把它发送到某个特定的地方,那个地址必须是正确的。

        数组就像你的房子——它存在于某个地方,所以它一个地址。正确处理的事情会被发送到那里。

        简而言之:

        指针持有地址。

        一个数组一个地址。

        所以

        int *array;
        

        创建一个不确定值的指针(它可以指向任何地方!)。

        当你有的时候

        array[9999] = 30;
        

        您正在尝试将第 9999 个 intarray 指向的位置设置为 30。但是您不知道 array 指向的位置,因为您没有给它一个实际值。

        这是未定义的行为。

        【讨论】:

          【解决方案6】:

          int array[100] 表示变量array 将能够保存 100 个 int 值,此内存将从堆栈中分配。变量array 将具有数组的基地址,并将为其分配内存。

          但在int *array 的情况下,由于您将其声明为局部变量,因此指针变量array 将具有垃圾地址。因此,如果您执行array[9999],则可能会导致分段违规,因为您正在尝试访问程序外部的垃圾内存位置。

          【讨论】:

          • 访问array[9999] 并不总是会导致段冲突。该行为未由 C 标准定义。地址可能在可访问内存中,或者代码可能会通过优化以意想不到的方式进行转换。
          • 是的,没错。但在大多数情况下会发生崩溃。
          • 答案可能是越界访问数组通常会导致段冲突,但不应让读者相信他们可能会期待这种行为。答案应包含真实陈述,不应包含虚假陈述。
          • >typedef struct edge{int dest ;int cost ;struct edge ∗next ;} ∗EList ; >typedef EList Graph[100] 所以如果我有类似的东西我可以做: EList hash; hash[30]=NULL,因为当我声明 EList hash 时,通过在 type 上声明它的大小,它会自动创建一个大小为 100 的哈希表,对吗?
          【解决方案7】:

          不同的是,当你做int array[100]时,100 * sizeof(int)的内存块分配在上,但是当你做int *array时,你需要动态分配内存(用@例如 987654324@ 函数)使用array 变量。动态分配的内存在 heap,而不是 stack

          【讨论】:

          • 问题没有显示这些声明是出现在函数内部还是外部,这会影响内存的分配方式。并且如何提供内存取决于实现。此外,不需要动态分配内存来使用指针。指针可以设置为指向其他内存,例如在另一个数组中。
          猜你喜欢
          • 1970-01-01
          • 2020-11-17
          • 2016-06-10
          • 2013-05-26
          • 2020-09-10
          • 2013-05-20
          • 1970-01-01
          • 1970-01-01
          • 2022-01-02
          相关资源
          最近更新 更多