c 语言新手问题:数组是如何记录元素数量的?

2016-05-24 10:54:11 +08:00
 wohenyingyu01
比如:
int a[10]={0};
a 这个数组变量的值是第一个元素的首地址:
print("%p\n",a);
等同于
print("%p\n",&a[0]);
意味着 a 根本不知道自己指向的地址后面还有多少个元素?
那么 sizeof(a)是如何计算出数组总长度的呢?
2585 次点击
所在节点    问与答
16 条回复
msg7086
2016-05-24 11:01:38 +08:00
sizeof 并没有计算数组的数量。
sizeof 是关键字,取的是源代码中预先给定的大小。
比如 int a[10]的大小是 40 ,因此 sizeof(a) 就是 40 。
也就是说, int size = sizeof(a); 经过编译以后会变成 int size = 40; 。
lsmgeb89
2016-05-24 11:11:29 +08:00
一句题外话,好像记得编译器会把数组元素的个数存在数组首地址前的 4 bytes 里。
wohenyingyu01
2016-05-24 11:21:17 +08:00
@msg7086 确实,突然发现原来声明数组的时候长度不能用变量表示……高级语言看多了,容易惯性思维哈哈。
msg7086
2016-05-24 11:25:42 +08:00
@wohenyingyu01
https://zh.wikipedia.org/wiki/C 语言#C99
支持不定长的数组,即数组长度可以在运行时决定,比如利用变量作为数组长度。声明时使用 int a[var] 的形式。
jonah
2016-05-24 11:25:43 +08:00
sizeof 是编译期行为。
am241
2016-05-24 11:31:29 +08:00
编译期间会保存,编译结束后就丢了。所以 sizeof 是语句而不是函数。
有个东西叫 countof ,是一个宏,可以了解一下。
stackpop
2016-05-24 11:32:24 +08:00
@wohenyingyu01
静态数组可以这么算,但是动态数组不行。
int* a = new int[100];
并不能通过 a 推断出数组长度,另外函数接口通常的做法也是类似下面这样
int f(int * arr, int len)
需要同时提供地址和长度

并非一定不能用变量,

int n = 10;
int p[n];

这样的语法是符合 C99 标准的,但是在 C++中似乎不合法, G++需要使用扩展-pedantic 才支持。具体你可以自己测试。
gamexg
2016-05-24 12:37:51 +08:00
最烦的就是每次传递一个数组,需要另行传递长度。
hitmanx
2016-05-24 13:04:18 +08:00
如果是分配在栈里的 fix 大小的数组,编译器在编译时就能知道大小,会直接替换为对应分配的代码。即使是动态数组,长度是在运行时才能确定的, heap manager 也会在申请时记录它的大小,要不然删除时(delete[])如果不知道当初分配了多大,怎么能知道要释放多少呢?至于它实现方式可以是多样的,可以像 2 楼说的,在返回的地址前额外分配一个 size_t 的大小来保存数组的长度,或者直接拿个表来存应该也可以
hitmanx
2016-05-24 13:10:23 +08:00
@hitmanx 好像跑题了。就 sizeof 来说,首先它是编译期的计算,其次编译器不光要知道长度,还需要用到它在内存中的排列方式,因为可能会有对齐存在,最后编译器还要帮我们在栈里预留这么大的空间,如果这些编译器都能帮我们搞定,你为啥觉得它会连大小都算不出来
wohenyingyu01
2016-05-24 13:53:55 +08:00
@stackpop 我那种申请方式数组储存在栈中,你用 new 数组就是在堆中了,这么一说来我就有点理解了,栈内存不能在运行时分配大小也符合逻辑。

这和动态静态数组没关系吧,比如 char string[]="USA"和 char *string2="USA", string 可以用 sizeof 判断而 string2 不可以,应该是数组类型和指针类型的差距。

int n = 10;
int p[n];

这个写法在 ANSI C 里面是不合法的,但是可以这样:

const int n = 10;
int p[n];
wohenyingyu01
2016-05-24 13:58:54 +08:00
@hitmanx 嗯嗯,但是貌似我看的好多 c 语言的书都没有提到它是如何记录长度的,大多只是告诉你就是这样用的,所以会隐约感到逻辑不对。
stackpop
2016-05-24 14:01:50 +08:00
@wohenyingyu01

我表述不够严谨,原义和你差不多。

另外后面那个我没有说 ANSI C 是合法的。我说的是 C99 是合法的,你自己写程序验证吧。
but0n
2016-05-24 15:43:16 +08:00
当数组作为参数传递时会发生退化,所以数组长度需要另外传值

数组和指针的关系至今没弄懂

有人说,数组是不是指针的指针
hitmanx
2016-05-24 15:59:35 +08:00
@wohenyingyu01 有时间的话可以看看斯坦福的公开课<编程范式>,当初对我帮助巨大,尤其是假如你像我当初一样之前没有系统地学过编译原理、操作系统的话。你的这些疑问,里面都会讲到。

地址在这儿: http://open.163.com/special/opencourse/paradigms.html
abutter
2016-05-24 16:03:31 +08:00
标准(或者说传统) C 中,数组的大小是编译时确定的,因为长度是确定的,类型长度也是确定的,所以遇到 sizeof 就是直接替换成其编译时确定的值。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/280843

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX