初识C语言指针

初识c语言指针

作为一只java汪,平时不会去关注指针方面的知识,这两天在看csapp时,看见指针好像能做一些有趣的事情,决定把当初学C语言时把我弄的晕头转向的指针好好看看,总结一下。

指针是什么?

我们常常听一些大神说,指针很简单啊,无非是一个存着指向某个地址空间的变量而已,其实要弄懂这个,需要从了解计算到底是以一个怎样的形式来存储信息开始看。

机器其实没有我们人这么聪明,他能快速理解的就是0,1这样的信息,也就是我们说的位,单纯的来讲,一个位并不能表示什么很有用的信息,但是如果我们用一段序列的位来表示信息,如8位来表示某个信息,算一算我们可以有多少种组合?如果32位呢?64位呢?

信息的存储

在大多的计算机上使用8位的块为一个最小的可寻址单位,我们也称作字节,操作系统的形成是为了我们更方便的与底层硬件交互,操作系统提供给我们一个大的虚拟存储器,看起来像一个超级大的字节数组,每个字节都有唯一一个标识他的数字,也就是地址

下面给出一个整数类型的变量在内存中存储的形式

我们可以看到,一个int类型的变量是占了连续的4个字节的存储空间,但是在我们写的文本代码被编译器翻译成机器码时,机器会忽略变量的类型,对于机器码来说说,会被翻译成,从首地址地址0x100开始,向后读取4个字节。所以我们的一个int类型的变量可以用指针来读取,一个指向int类型的指针中存储的值就是某个int类型变量的首地址。指针也是一个变量,只是他有特殊的含义而已。
一般来说,一个指针变量所占的字节数与机器使用的字长有关,32位的机器使用4个字节来存储指针变量,64位的机器使用8个字节来存储指针,很好理解,因为指针是用来表示地址的,如果不是足够长度的位数来表示指针,那么对于内存较大的机器,会有一些存储空间根本无法访问。

一个关于指针的小例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<stdio.h>
typedef unsigned char* byte_pointer;

void show_byte(byte_pointer start,int len){
int i;
printf("0x");
for(int i = len-1;i>=0;i--){
printf("%.2x",start[i]);
}
printf("\n");
}
void show_int(int x){
printf("show_int(%d):\n",x);
show_byte((byte_pointer)&x,sizeof(x));
}
void show_pointer(void *x){
printf("参数x中存的内容:%x\n",x);
printf("参数x的地址:%x\n",&x);
printf("show_pointer:\n");
show_byte((byte_pointer)&x,sizeof(x));
}
int main(){
int x = 12345;
int y = 12346;
int *p_x = &x;
printf("&x(x变量的首地址)为:%x\n",&x);
printf("*p_x : %d\n",*p_x);
printf("p_x : %x\n",p_x);
printf("y:%d\n&y:%x\n*(p_x+1):%d\n",y,&y,*(p_x+1));
printf("p_x+1:%x\n",p_x+1);
show_int(x);
show_int(y);
printf("&p_x(p_x的首地址):%x\n",&p_x);
show_pointer(p_x);
return 0;
}

某次运行的结果(os:linux 64 bit):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
&x(x变量的首地址)为:10f5328
*p_x : 12345
p_x : 10f5328
y:12346
&y:10f532c
*(p_x+1):12346
p_x+1:10f532c
show_int(12345):
0x00003039
show_int(12346):
0x0000303a
&p_x(p_x的首地址):10f5330
参数x中存的内容:10f5328
参数x的地址:10f5308
show_pointer:
0x00007ffd010f5328

对于上面的结果,我想提几个问题,看看大家能否答的上来

  • p_x+1为什么是10f532c而不是10f5329呢?
  • 验证下0x3039转换成十进制的值是12345吗?
  • 使用show_pointer()打印的p_x的值和直接打印的p_x的值少了4个字节(32位),不是说指针在64位操作系统下是占8个字节吗?这里我也不明白
  • show_pointer()函数中的形参x的首地址和实参p_x的首地址差了多少?现在你明白为什么说传入参数时是对形参进行了一次赋值操作了吗?
  • 加个总结 c语言中
    *:相当于取值操作
    &:取变量地址

五花八门的指针

我们经常被指针弄的晕头转向的原因就是关于指针有各种各样的操作,小小指针带来的灵活操作各有不同的名字 ,我们常常被这些名词唬住,什么指针常量,常量指针,指针变量,指针的指针,指针函数,函数指针。。。WTF?不要被这些概念弄混,我们要透过现象看本质。好好理解上面说的指针是什么,下面我们举例看看指针的各种用法吧。