C/C++:sizeof数组与指针

97 篇文章 7 订阅

C/C++:sizeof数组与指针

在C/C++中使用sizeof对数组和指针所得的结果是不一样的。

[例1]

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

#define SAFE_FREE(p) {free(p);p=NULL;}

int main()
{
    char arr[20];
    char *p = (char *)malloc(sizeof(char) * 20);
    printf("sizeof arr :%d\n", sizeof(arr));
    printf("sizeof p :%d\n", sizeof(p));

    SAFE_FREE(p);   

    return 0;
}

输出:

[test1280@localhost 20170416]$ ./main
sizeof arr :20
sizeof p :4

sizeof一个变量得到这个变量所占用的字节数。

使用sizeof对一个数组操作(sizeof是一个操作符,而不是一个函数),得到的是这个数组占用的内存字节数。

有可能会这么想:使用sizeof对一个指针操作,得到的将会是指针指向的空间所占用的字节数?

并不是!

指针是啥?指针是个变量,既然是变量,那你sizeof一个指针变量,得到的结果当然是这个指针变量占据的字节数。

一个指针变量是做什么用的?要标识一个地址,这个地址在整个计算机内是全局唯一的。

如果计算机最多寻址4G有32地址线,你用16位的一个变量能唯一标识吗?显然不可以。

一个指针变量的大小不仅和计算机本身硬件、操作系统有关,而且还和你的编译器有关系。

完全可能是在64位机上使用编译器编译出来的一个指针变量占据的大小是4字节。

注:下面所进行的所有试验都是基于以下环境:

[test1280@localhost 20170416]$ uname -a
Linux localhost.localdomain 2.6.32-431.el6.i686 #1 SMP Fri Nov 22 00:26:36 UTC 2013 i686 i686 i386 GNU/Linux
[test1280@localhost 20170416]$ gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18)
Copyright (C) 2010 Free Software Foundation, Inc.

例1说明:

数组名和指针变量还是有区别的,虽然他们都可以通过[]或者*来访问变量/数组。

对一个指针变量用sizeof操作,得到的结果永远是指针变量本身的大小,而不是指针变量指向的空间的大小。

[例2]

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

#define SAFE_FREE(p) {free(p);p=NULL;}

void foo(char arr[], char *p) 
{
    printf("sizeof arr :%d\n", sizeof(arr));
    printf("sizeof p :%d\n", sizeof(p));
}

int main()
{
    char arr[20];
    char *p = (char *)malloc(sizeof(char) * 20);

    foo(arr, p); 

    SAFE_FREE(p);   

    return 0;
}

输出结果为:

[test1280@localhost 20170416]$ ./main 
sizeof arr :4
sizeof p :4

结论:

数组在进行函数调用作为参数被传递时,在被调用函数内部其退化为指针,使用sizeof等价于对一个指针变量进行sizeof,大小为一个指针变量所占的内存空间。

通常我们可以看到,一个形参是数组类型的,或者是指针类型的,都包含了另一个形参,是个整型值,用来标识数组类型(指针类型)的大小的,因为在被调用函数内部不知道其大小呀!


下面介绍下sizeof。

sizeof是一个操作符,而不是一个函数,其返回值是size_t类型。

sizeof是编译时进行的,也就是说,其值的大小,是在运行之前就已经决定好的,不像函数调用,是在运行期间决定的。

sizeof的对象可以是一个类型,也可以是一个变量。

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

int main()
{
    printf("%d\n", sizeof(char));
    printf("%d\n", sizeof(int));

    char c;
    int i;

    printf("%d\n", sizeof(c));
    printf("%d\n", sizeof(i));

    printf("%d\n", sizeof c); 
    printf("%d\n", sizeof i); 

    return 0;
}

编译运行都OK。

注意下面的程序:

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

int main()
{
    printf("%d\n", sizeof char);
    printf("%d\n", sizeof int);

    return 0;
}

编译报错:

[test1280@localhost 20170416]$ gcc -o main main.c -Wall
main.c: In function ‘main’:
main.c:6: error: expected expression before ‘char’
main.c:7: error: expected expression before ‘int

总结:

使用sizeof有三种正确方式:

sizeof(type_name);
sizeof(var);
sizeof var;

但是sizeof type_name是错误的。

建议:

使用sizeof时,统一都加上括号吧。

[例3]

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

int main()
{

    int n = 0;
    printf("%d\n", sizeof(n=100));
    printf("%d\n", n); 

    return 0;
}

输出:

[test1280@localhost 20170416]$ !g
gcc -o main main.c -Wall
[test1280@localhost 20170416]$ ./main
4
0

为什么输出是0呢?关键在于,sizeof是在编译阶段就已经确定了的,表达式:

n = 100

这是一个赋值表达式,操作符=返回左操作数的类型,也就是int。

所以,在编译完成之后,运行之前,实际上就是等价于输出sizeof(int)。

由于sizeof不能被编译成机器码,所以sizeof作用范围内,也就是()里面的内容也不能被编译,而是被替换成类型。

[例4]

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

char char_f(){return 'a';}
int int_f(){return 0;} 
double double_f(){return 0;} 
void void_f(){}

int main()
{

    printf("%d\n", sizeof(char_f()));
    printf("%d\n", sizeof(int_f()));
    printf("%d\n", sizeof(double_f()));
    printf("%d\n", sizeof(void_f())); 

    printf("\n");

    printf("%d\n", sizeof(void));

    printf("\n");

    printf("%d\n", sizeof(char_f));
    printf("%d\n", sizeof(int_f));
    printf("%d\n", sizeof(double_f));
    printf("%d\n", sizeof(void_f));

    return 0;
}

输出:

[test1280@localhost 20170416]$ !g
gcc -o main main.c -Wall
[test1280@localhost 20170416]$ ./main
1
4
8
1

1

1
1
1
1
[test1280@localhost 20170416]$ 

首先前四个比较好理解,sizeof返回的是各个函数的返回值的类型的大小;
对于void来说,使用sizeof得到的是1;
末尾的四个1我暂时无法解释,留待日后解释,或者有朋友来帮我解释下~谢谢啦~
(注:函数名仅仅是个符号,代表一个地址,应该也是4,为什么是1?)

[例5]

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

int main()
{
    double* (*a)[3][6];

    printf("%d\n", sizeof(a));      //4 
    printf("%d\n", sizeof(*a));     //3*6*4
    printf("%d\n", sizeof(**a));    //6*4
    printf("%d\n", sizeof(***a));   //4 
    printf("%d\n", sizeof(****a));  //8 

    char arr[5][8];
    printf("%d\n", sizeof(*arr));   //8 

    return 0;
}

输出:

[test1280@localhost 20170416]$ !g
gcc -o main main.c
[test1280@localhost 20170416]$ ./main
4
72
24
4
8
8

对例5的解释:

a是啥?a首先是一个指针,类似于int (*a);

所以,sizeof(a)等同于sizeof(char *),也就是4(可能是8);

这个指针指向一个什么类型的数据呢?
比对int (a),指向一个int类型的数据,那么也就不难理解,这里的a指向一个double*[3][6]类型的数据;

所以*a就代表了这样的一个数据实体,里面每一个元素都是一个指针,指向一个double对象,共有这样的指针多少个呢?3*6=18个,每个指针多大呢?4字节,所以结果就是3*6*4=72;

**a从含义上来说等价于*arr;

arr是一个指向数组的指针,是数组级别的;
*arr是一个指向数组中某一行的指针,是行级别的;
**arr是一个指向数组中某一个元素的指针,是元素级别的。

而sizeof(arr)结果是对行所有元素求大小,即一行的元素数量每个元素的大小,所以sizeof(*arr)结果是8*1=8;

回想这里的**arr,结果自然就是6*4=24;

***arr上面已经说了,这是一个具体的对象了,这时具体的对象是一个double类型指针,所以是4(或者8);

****arr是什么类型的呢?是一个double类型,结果就是8。

基本上就是这样理解的。

额,最后来看个简单的小程序:

[例6]

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

#define ARRAY_SIZE(arr, type_name) (sizeof(arr)/sizeof(type_name))

int main()
{
    char arr[] = "abcdef";
    char *p = arr;

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

    // 获得数组大小(以元素为单位)的方式
    int array[] = {1, 2, 3, 4, 5, 6}; 
    printf("%d\n", ARRAY_SIZE(array, int));

    char s[2048] = "abcdefgh";
    // 输出2048,初始化是初始化,已经确定了数组大小的情况下不会影响数组的大小,并不是9
    printf("%d\n", sizeof(s));

    return 0;
}

输出:

[test1280@localhost 20170416]$ gcc -o main main.c
[test1280@localhost 20170416]$ ./main
7
4
6
2048

值得注意的是使用一个宏来求一个数组大小的这种方式。

但是也是有前提的,必须是在可识别数组大小(sizeof 数组正确时)才是成立的,毕竟宏也仅仅是做一个替换。

参考来源:

1.http://blog.csdn.net/luguifang2011/article/details/39988627
2.http://blog.csdn.net/kangroger/article/details/20653255
3.http://www.cnblogs.com/qingergege/p/5943764.html

  • 12
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
数组名和指针sizeof是不同的。根据引用中的解释,数组名和指向该数组指针在地址上是相同的,但是它们的大小不同。数组名的sizeof返回的是整个数组的大小,而指针sizeof返回的是指针类型的大小。所以,sizeof数组名会返回整个数组的大小,而sizeof指针会返回指针类型的大小。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [探讨C++数组名与指针的用法比较分析](https://download.csdn.net/download/weixin_38691256/14871672)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [C++/C中 sizeof(指针)和sizeof(数组名)的区别](https://blog.csdn.net/weixin_38383877/article/details/90922929)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [c 语言中的sizeof数组名)和sizeof(指针)](https://blog.csdn.net/Colorful_lights/article/details/79819682)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值