V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
wohenyingyu01
V2EX  ›  问与答

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

  •  
  •   wohenyingyu01 · 2016-05-24 10:54:11 +08:00 · 2586 次点击
    这是一个创建于 3100 天前的主题,其中的信息可能已经有所发展或是发生改变。
    比如:
    int a[10]={0};
    a 这个数组变量的值是第一个元素的首地址:
    print("%p\n",a);
    等同于
    print("%p\n",&a[0]);
    意味着 a 根本不知道自己指向的地址后面还有多少个元素?
    那么 sizeof(a)是如何计算出数组总长度的呢?
    16 条回复    2016-05-24 16:03:31 +08:00
    msg7086
        1
    msg7086  
       2016-05-24 11:01:38 +08:00   ❤️ 1
    sizeof 并没有计算数组的数量。
    sizeof 是关键字,取的是源代码中预先给定的大小。
    比如 int a[10]的大小是 40 ,因此 sizeof(a) 就是 40 。
    也就是说, int size = sizeof(a); 经过编译以后会变成 int size = 40; 。
    lsmgeb89
        2
    lsmgeb89  
       2016-05-24 11:11:29 +08:00
    一句题外话,好像记得编译器会把数组元素的个数存在数组首地址前的 4 bytes 里。
    wohenyingyu01
        3
    wohenyingyu01  
    OP
       2016-05-24 11:21:17 +08:00
    @msg7086 确实,突然发现原来声明数组的时候长度不能用变量表示……高级语言看多了,容易惯性思维哈哈。
    msg7086
        4
    msg7086  
       2016-05-24 11:25:42 +08:00
    @wohenyingyu01
    https://zh.wikipedia.org/wiki/C 语言#C99
    支持不定长的数组,即数组长度可以在运行时决定,比如利用变量作为数组长度。声明时使用 int a[var] 的形式。
    jonah
        5
    jonah  
       2016-05-24 11:25:43 +08:00   ❤️ 1
    sizeof 是编译期行为。
    am241
        6
    am241  
       2016-05-24 11:31:29 +08:00 via Android   ❤️ 1
    编译期间会保存,编译结束后就丢了。所以 sizeof 是语句而不是函数。
    有个东西叫 countof ,是一个宏,可以了解一下。
    stackpop
        7
    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
        8
    gamexg  
       2016-05-24 12:37:51 +08:00 via Android
    最烦的就是每次传递一个数组,需要另行传递长度。
    hitmanx
        9
    hitmanx  
       2016-05-24 13:04:18 +08:00   ❤️ 1
    如果是分配在栈里的 fix 大小的数组,编译器在编译时就能知道大小,会直接替换为对应分配的代码。即使是动态数组,长度是在运行时才能确定的, heap manager 也会在申请时记录它的大小,要不然删除时(delete[])如果不知道当初分配了多大,怎么能知道要释放多少呢?至于它实现方式可以是多样的,可以像 2 楼说的,在返回的地址前额外分配一个 size_t 的大小来保存数组的长度,或者直接拿个表来存应该也可以
    hitmanx
        10
    hitmanx  
       2016-05-24 13:10:23 +08:00
    @hitmanx 好像跑题了。就 sizeof 来说,首先它是编译期的计算,其次编译器不光要知道长度,还需要用到它在内存中的排列方式,因为可能会有对齐存在,最后编译器还要帮我们在栈里预留这么大的空间,如果这些编译器都能帮我们搞定,你为啥觉得它会连大小都算不出来
    wohenyingyu01
        11
    wohenyingyu01  
    OP
       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
        12
    wohenyingyu01  
    OP
       2016-05-24 13:58:54 +08:00
    @hitmanx 嗯嗯,但是貌似我看的好多 c 语言的书都没有提到它是如何记录长度的,大多只是告诉你就是这样用的,所以会隐约感到逻辑不对。
    stackpop
        13
    stackpop  
       2016-05-24 14:01:50 +08:00
    @wohenyingyu01

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

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

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

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

    地址在这儿: http://open.163.com/special/opencourse/paradigms.html
    abutter
        16
    abutter  
       2016-05-24 16:03:31 +08:00
    标准(或者说传统) C 中,数组的大小是编译时确定的,因为长度是确定的,类型长度也是确定的,所以遇到 sizeof 就是直接替换成其编译时确定的值。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3610 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 04:33 · PVG 12:33 · LAX 20:33 · JFK 23:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.