一、运算符sizeof()

c语言给出了一个工具,有一个运算符叫做sizeof(),这个sizeof()可以给出某个类型或变量在内存中所占据的字节数。比如说sizeof(int )告诉你int占据了几个字节;sizeof(a),会告诉你a这个变量了占据几个字节。
我们来试一下sizeof这个事情:

#include<stdio.h>
int main()
{
	int a;
	a=6;
	printf("sizeof(int)=%d\n",sizeof(int));
	printf("sizeof(a)=%d\n",sizeof(a));	
	printf("sizeof(double)=%d\n",sizeof(double));	
	return 0;
 } 

运行结果为:

拿int来分析运行结果:int在内存中占据了4个byte(字节),1个byte=8个bit(位),所以4个byte意味着这是一个32位的变量,这个变量在内存中要占据4个byte,或者说占据32个bit。

二、运算符&
1.scanf函数里一定要有&符号,如果变量前面不加&符号,程序就会出错。

2.&不能取的地址
scanf(“%d”,&i);里的&,作用是获得变量的地址,它的操作数必须是变量。
&不能对没有地址的东西取地址:

  • &(a+b)?✖
  • &(a++)?✖
  • &(++a)?✖
  • 在&右边必须有一个明确的变量,才能去取它的地址。

3.为什么变量会有地址?因为c语言的变量是放在内存里面的,每一个变量(上面用sizeof()看过都有相应占据的字节,这些字节在内存中占据一定的地方,它放在某一个地方,它就有一个地址。所以运算符&就是把那个变量的地址拿出来告诉你。

4.那么这个地址会是怎样一个值呢?
我们在64位架构下运行以下代码:

#include<stdio.h>
int main()
{
	int i=0;
	int p;
	p=(int)&i;
	printf("0x%x\n",&i);
	printf("%p\n",&i);	
	printf("0x%x\n",p);	
	printf("%lu\n",sizeof(int));
	printf("%lu\n",sizeof(&i));	
	return 0;
 } 

程序运行会出现warning,[Warning] cast from pointer to integer of different size [-Wpointer-to-int-cast]。
我们先不管这个warning,运行结果如下:

可以看到在64位架构下int是4个字节,而变量i是8个字节。这里说明一下在32位架构上运行以上代码,输出的int和i都会是4个字节。
总结:运算符&可以为我们取出一个变量的地址,但是这个地址的大小、地址的数据类型和int类型是否相等取决于编译器,取决于是64位架构还是32位架构。所以当我们要让printf为我们输出一个地址时,我们需要用%p,而不是真的直接把它当做一个整数。地址和整数并不永远是相同的,这和架构是有关的。

5.再来对&做一些深入研究
(1):取相邻的变量的地址

#include<stdio.h>
int main()
{
	int i=0;
	int p;
	printf("%p\n",&i);
	printf("%p\n",&p);	
	return 0;
 } 

设置两个变量i和p,程序运行结果:

可以看到在16进制下,一个变量的地址是4C,另外一个是48,C相当于16进制的12,两者相差4。这就说明在内存中,这两个变量是紧挨着放的:

i是先定义的变量,p是后定义的变量。在内存中i在更高的地方,p在更低的地方。这个问题在c语言的内存模型中会讲到。这两个变量都是本地变量,它们分配在内存的一种叫做堆栈(stack)的地方,在堆栈里面,分配内存是自顶向下来分配的。
(2):数组的地址、数组单元的地址、相邻的数组单元的地址:
定义一个int数组,尝试如下输出:

#include<stdio.h>
int main()
{
	int a[10];
	printf("%p\n",&a);//取出a的地址 
	printf("%p\n",a);//把a当做一个地址尝试输出 
	printf("%p\n",&a[0]);//取出a[0]的地址 
	printf("%p\n",&a[1]);//取出a[1]的地址 
	return 0;
 } 

结果如下:

分析运行结果,可以发现:
&a等于a等于a[0];相邻的int数组单元的地址差距永远是4。