c语言初阶指针详解,初学者适用

本节知识点:

1.指针是什么

2.指针和指针类型

3.野指针

4.指针运算

5.指针和数组

6.二级指针

7.指针数组

一、指针是什么

指针理解的两个要点:

1.指针是内存中一个最小单元单元的编号,也就是地址

2.平时口语中说的指针,通常指的是指针变量,用来存放地址的变量

下面我们来详细解释一下指针:

内存是一块很大的空间,为了更好的管理,我们把它划分成一个个小的内存单元,一个基本的内存单元的大小是一个字节。我们把每一个内存单元都进行编号,就像对房间进行编号,这个编号就称为地址,这样我们就能快速的找到我们所要寻找的内存单元。

而内存单元的编号/地址/指针表达的都是一个意思

拓展补充地址编号怎么产生:

32位机器----有32个地址线,就是物理的电线--对电线通电与否,就会产生0/1两种结果,即电信号转化为数字信号,就会产生如下的结果:

00000000 00000000 00000000 00000000 

00000000 00000000 00000000 00000001

......

01111111 11111111 11111111 11111111

10000000 00000000 00000000 00000000 

......

11111111 11111111 11111111 11111111

这些二进制序列就作为编号

二、指针和指针类型

1、指针变量

我们通过&(取地址操作符)取出变量的内存起始地址,把地址存放在一个变量中,这个变量就是指针变量。即指针变量,用来存放地址的变量。

指针变量的大小:
在32位的机器上,地址是32个0/1组成的二进制序列,那么地址就需要4个字节的空间来存储,所以一个指针变量的大小就是4个字节。(1字节=8 bit,所以32 bit=4字节)

同理,在64位机器上,一个指针变量的大小是8字节。

2、指针类型

既然指针大小都是固定的,那定义指针类型的意义在哪呢?

第一个意义:指针类型决定了在解引用时一次能访问几个字节(指针的权限)

下面我们看这两个代码

#include <stdio.h>
int main()
{
	int a =0x11223344;
	int* pa = &a;
	*pa = 0;
	
	char* pc = &a;
	*pc = 0;
	//指针类型决定了在解引用时一次能访问几个字节(指针的权限)
	//int*   4个字节
	//char*  1个字节
	//double*  8个字节
}

那么这个有什么作用呢?

如在一块内存中,如果我们想要访问四个字节,我们可以使用 int* / float*型指针;如果我们想要访问一个字节,我们可以使用 char*型指针。

第二个意义:决定了指针向前或向后走一步,走多大距离(单位是字节)

#include <stdio.h>
int main()
{
	int a = 10;
	int* pa = &a;
	char* pc = &a;
	printf("%pn", pa);
	printf("%pn", pa+1);
	printf("%pn", pc);
	printf("%pn", pc+1);
	return 0;
}

这个是上述代码的运行结果: 

 三、野指针

3.1 野指针的成因

1.指针未初始化

int main()
{
	int* p;  //局部变量未初始化,默认为随机值
	*p = 20;
	return 0;
}

2.指针越界访问

int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	for (i = 0; i <= 10; i++) //当前指针指向的范围超出数组arr的范围时,p就是野指针
	{
		*p = i;
        p++;
	}
	return 0;
}

3.指针指向的空间释放了

int* test()
{
	int a = 100;
	return &a;
}
int main()
{
	int* p=test();
	printf("%d", *p);//出了test函数,a就被销毁了
	return 0;
}

 这里的销毁不是真正意义上的销毁,是使用权还给系统了,比如这里p依然指向a的地址,但a的值可能变了,不一定是100了,是系统随机分配的值

3.2 如何规避野指针

1.指针初始化:两种初始化形式

int main()
{
	int a = 0;
	int* pa = &a;//明确知道指向谁
	 
	int* p = NULL;//不知道指向谁是,就指向NULL
	return 0;
}

2.小心指针越界

3.指针指向空间释放及时置NULL

4.避免返回局部变量的地址

5.指针使用之前检查有效性

判断有效性的语句:if(p != NULL)

四、指针运算

1.指针+-整数

例题:利用指针来打印10-1

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i + 1;
	}
	int* q = &arr[9];
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *q);
		q--;
	}
	return 0;
}

输出结果如下:  

2.指针-指针

指针-指针的前提是:两个指针指向同一块空间

int main()
{
	int arr[10] = { 0 };
	printf("%dn", &arr[9] - &arr[0]); //两个地址相减,减出来是两个地址间元素的个数
	printf("%dn", &arr[0] - &arr[9]);  
	return 0;
}

输出结果如下:

 

3.指针的关系运算(指针比较大小)

for (vp = &valuse[N_VALUSE]; vp > &valuse[0];)
	{
		*--vp = 0;
	}

五、指针和数组

数组和指针本身就是两种事物,联系就是可以通过指针访问数组

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		printf("%p == %pn", p + i,&arr[i]);
	}
}

输出结果如下:

六、二阶指针 

int main()
{
	int a = 10;
	int* pa = &a;
	int** ppa = &pa;//ppa就是一个二级指针
	int*** pppa = &ppa;//pppa就是一个三级指针
    **ppa = 20;
	printf("%dn", a);//通过二级指针访问a
	return 0;
}

pa存放的是a的地址

ppa存放的是pa的地址

pppa存放的是ppa的地址

七、指针数组

int main()
{
	int arr[10];//整型数组--存放整型的数组
	char ch[5];//字符数组--存放字符的数组
	int a = 10;
	int b = 20;
	int c = 30;
	int* arr2[5] = {&a, &b, &c};//指针数组--存放指针的数组
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%d ", *(arr2[i]));
	}
	return 0;
}

输出结果如下: 

 

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>