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