【问题标题】:Size of array stays the same even after adding more elements with values to the array即使在向数组中添加更多具有值的元素后,数组的大小也保持不变
【发布时间】:2015-12-18 17:34:48
【问题描述】:

这只是我今天在玩一些代码时学到的东西。我还是C新手,请多多关照。

下面的代码基本上是获取一个只有一个元素的数组并检查它的大小和值(分别为 4 和 0)。然后它在数组中创建新元素并为这些新元素分配值,然后再次检查数组的大小。

我发现数组的大小没有增加。如果我从开始创建包含 5 个元素的数组,则数组大小为 20。如果我从开始只创建 1 个元素并稍后添加其他 4 个元素,则数组大小保持为 4,但仍包含 5 个元素的值。

有人能解释一下为什么会这样吗?这是一种在节省空间的同时为数组赋值的安全方法吗?还是这有什么问题?

我错过了什么吗?

如果我在错误的 Stack Exchange 论坛上发布了此内容,请告诉我,以便我删除它并在其他地方提问,谢谢。

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

int main()
{
    int n = 5; 
    char temps[257] = "1 -2 -8 4 5\n"; 
    int arr[1] = {0};
    int c;   

printf("\n-- START of Test area --\n\n");

// sizeof arr = 4
printf("Initial sizeof(arr) = %d\n\n", sizeof(arr));

// Initial values of arr
printf("Value of arr[0] = %d\n", arr[0]);    // 0
printf("Value of arr[1] (no value assigned) = %d\n", arr[1]);    // random number
printf("Value of arr[2] (no value assigned) = %d\n\n", arr[2]);    // Random number

// sizeof arr = 4
printf("sizeof(arr) = %d\n\n", sizeof(arr));

// -- Creates new array elements and assigns values using temps 
sscanf(temps, "%d\n %d\n %d\n %d\n %d\n", &arr[0], &arr[1], &arr[2], &arr[3], &arr[4]);    

printf("New array elements and values using temps\n\n");
printf("Value of arr[0] = %d\n", arr[0]);  // 1
printf("Value of arr[1] = %d\n", arr[1]);  // -2
printf("Value of arr[2] = %d\n", arr[2]);  // -8
printf("Value of arr[3] = %d\n", arr[3]);  // 4
printf("Value of arr[4] = %d\n", arr[4]);  // 5
printf("Value of arr[5] = %d\n\n", arr[5]);  // 0

// Sizeof array = 4
printf("sizeof(arr) = %d\n\n", sizeof(arr)); 

printf("\n-- END of Test area --\n\n");

    return 0;
}

【问题讨论】:

  • 当代码命中 int arr[1] = {0}; ....printf("Value of arr[1] (no value assigned) = %d\n", arr[1]); 时,它访问了数组边界之外的内存 --> 未定义的行为。其余代码没有真实性。

标签: c arrays sizeof


【解决方案1】:

一旦声明了一个数组,就不能在其中添加或减去任何元素,但可以修改。
另一件事是 arr 的大小为 1 并且您在某些语句中访问数组超出范围,例如

sscanf(temps, "%d\n %d\n %d\n %d\n %d\n", &arr[0], &arr[1], &arr[2], &arr[3], &arr[4]); 

它调用未定义的行为。

【讨论】:

  • 好的,很高兴知道。那么为什么编译器会继续运行呢?它没有抱怨或任何事情。
  • 因为“未定义的行为”意味着语言规范没有规定您的编译器在这种情况下应该如何操作。这是你不应该做的事情。你不能依赖编译器来牵你的手。欢迎来到 C 的世界
【解决方案2】:

根据定义,数组是一块连续的内存。这意味着您只能一次告诉编译器数组的大小,它会为您的数组分配内存。

例如,如果您编写int n[10];,编译器将在堆栈上为 10 个整数值保留内存(例如,每个 int 为 8 个字节)。

在这种情况下,n[9] 是数组包含的最后一个元素,因为 n[0] 是第一个。

让我更详细地解释一下: n 实际上是数组第一个元素的内存地址。实际上n[0]n 具有相同的内存地址。 如果你有int i; 来表示你想访问的数组的索引:

n[i] 告诉编译器查看内存位置n + (i * sizeof(int));

编译器知道数组的类型,所以当你使用n[i];时它知道如何计算出合适的地址

现在如果i 无效,编译器将提供一个可能包含垃圾的内存地址,或者您可能无法访问。如果你不小心,这会给你带来麻烦。

由于 C 是一种较低级别的语言,它不支持数组边界检查,也不会为您跟踪数组大小。这意味着您应该自己跟踪它!否则您将面临未定义行为的风险。

还有其他数据结构可以根据需要增长和收缩(例如链表),但这些数据结构通常使用“空闲存储”或“堆内存”,并且与在堆栈上分配的内置数组的工作方式不同。

【讨论】:

  • 详细信息:C 未指定数组边界检查。 C 在允许的范围内支持它 - 尽管不是必需的。
【解决方案3】:

当您声明一个数组时,无法访问 >= 设置的维度的元素。 设置的参数应该是常量并且在编译时是已知的

例如

int n;
int arr[n]; // error: this is not known in compilation-time

int arr[2];
arr[5] = 6; // error: arr[5] doesn't actually exists!

【讨论】:

  • C++ 绝对不允许可变大小的数组,但 C 允许。在这里阅读:gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
  • "...在编译时已知!"在 C99 中不是这样,在 C11 中是可选的。
  • 是的,我知道。但对我来说,如果我们将数组视为大小未知的同类型容器,那么认为程序仍然是一种糟糕的方式。还有很多其他方法可以使一组元素的大小可变!
猜你喜欢
  • 2020-09-03
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 2017-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多