[C语言学习]----初级指针

目录

1. 指针是什么

2. 指针和指针类型

2.1 指针+-整数

2.2 指针的解引用

2.3 指针类型的用途

3. 野指针

3.1 野指针成因

3.1.1 指针未初始化

3.1.2 指针越界访问

3.1.3 指针指向的空间释放

3.2 如何避免野指针的形成

4. 指针运算

4.1 指针+-整数

4.2 指针-指针

4.3 指针的关系运算

5. 指针和数组

6. 二级指针

7. 指针数组


 

1. 指针是什么


在了解指针之前我们需要知道什么是内存

内存是储存区域,内存中每个空间都有独立的一个编号(类似于每个人的学号)

内存编号就是地址也就是指针

 

指针理解的2个要点:
1. 指针是内存中一个最小单元的编号1个字节),也就是地址
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量

 指针变量:


我们可以通过&取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个变量就是指针变量

#include <stdio.h>
int main()
{
	int a = 10;//在内存中开辟一块空间
	int* p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
		          //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量中,p就是一个之指针变量。
	printf("%p",p);
	return 0;
}

00EFFB1C就是a的地址,存放在指针变量p


指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。

注:

指针变量是用来存放地址的,地址是唯一标示一个内存单元的


指针的大小32位平台是4个字节,在64位平

int num = 10;
p = &num;

台是8个字节(所有指针类型

2. 指针和指针类型
 

我们知道在变量中有不同的类型,整形,浮点型等

而在指针中也有这样的类型

当有这样的代码:

int num = 10;
p = &num;

要将&num(num的地址)保存到p中,我们知道p就是一个指针变量,那它的类型是怎样的呢?
 

我们给指针变量相应的类型

char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;

其实:


char* 类型的指针是为了存放 char 类型变量的地址
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址


如果用char*类型的指针存放int类型的变量会发生什么?

#include<stdio.h>
int main()
{
	int a = 0x11223344;
	int*pa = &a;
	char* pc = &a;
	*pc = 0;
	
	return 0;
}

a的地址存放的数据是0x11223344(由于编译器是小端存储所以内存中存储顺序是44 33 22 11

而我们把int a的地址存放在一个char*类型的指针变量中,再对指针变量进行解引用修改a的值时,可以观察到只修改了1个字节的地址 

 

总结: 不同的指针类型决定了指针进行解引用操作时,指针的权限有多大(例如:int*类型的指针只能访问4个字节的空间,char*类型的指针只能访问1个字节的空间)

2.1 指针+-整数

看下面这段代码:

#include<stdio.h>
int main()
{
	int a = 0x11223344;
	int*  pa = &a;
	char* pc = &a;

	printf("pa=%p\n", pa);
	printf("pc=%p\n", pc);

	printf("pa+1=%p\n", pa+1);
	printf("pc+1=%p\n", pc+1);

	return 0;
}

 

通过运行程序我们可以发现:

int*类型的指针+1,地址增加4(int*+1,跳过一个整形,向后走4个字节)

char*类型的指针+1,地址增加1(char*+1,跳过一个字符,向后走1个字节)

总结:指针的类型决定了指针的步长,向前或者向后走一步有多大(距离)

2.2 指针的解引用

通过指针变量存储的变量地址访问变量,可以改变变量大小

#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;
	*p = 5;
	return 0;
}

 

2.3 指针类型的用途

总结:

1.不同的指针类型决定了指针进行解引用操作时,指针的权限有多大

2.指针的类型决定了指针的步长

3. 野指针
 

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

3.1 野指针成因
 

3.1.1 指针未初始化

#include <stdio.h>
int main()
{
	int* p;//局部变量指针未初始化,默认为随机值,这时候p就为野指针
	*p = 20;
	return 0;
}

3.1.2 指针越界访问

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

当指针访问其他未申请空间时,就会造成指针越界访问 

3.1.3 指针指向的空间释放

 

#include<stdio.h>
int* test()
{
	int num = 100;
	return &num;
}

int main()
{
	int* p = test();//p接收了1个已经释放的局部变量的内存地址
	*p = 200;//对已经释放的地址进行修改,会造成野指针非法访问

	return 0;
}

3.2 如何避免野指针的形成
 

1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放,及时置NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性

#include<stdio.h>
int main()
{
	int a = 10;
	int* pa = &a;//明确初始化

	//NULL - 0,就是初始化指针的
	int* p = NULL;


	return 0;
}

 

4. 指针运算
 

4.1 指针+-整数
 

#include<stdio.h>
int main()
{
	int arr[5] = {1,2,3,4,5};
	int *p = arr;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", *(p + i));
	}

	return 0;
}

 

 

通过指针+-整数进行指针的偏移,访问其他地址

4.2 指针-指针

注:指针+指针无意义

指针-指针计算指针之间的元素个数:

#include<stdio.h>
int main()
{
	//两个指针相减的前提是:指针指向的同一块连续的空间
	int arr[10] = {0};
	printf("%d\n", &arr[9] - &arr[0]);
	printf("%d\n", &arr[0] - &arr[9]);


	return 0;
}

 

 注:

两个指针相减的前提是:指针指向的同一块连续的空间

4.3 指针的关系运算

比较指针之间的地址大小

#include<stdio.h>
int main()
{
    for (vp = &values[5]; vp > &values[0];)
    {
	    *--vp = 0;
    }

    return 0;
}

5. 指针和数组
 

我们先看这段代码:
 

#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}

运行结果:

可见数组名和数组首元素的地址是一样的 
 

结论:数组名表示的是数组首元素的地址(2种情况除外)


例外:1. sizeof(arr)

           2. &arr

 6. 二级指针

指针变量也是变量,是变量就有地址,指针变量的地址存放在二级指针中

#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;//p就是指针变量,一级指针变量

	int** pp = &p;//pp就是二级指针

	return 0;
}

 p存放a的地址,pp存放p的地址

 

 

 对于二级指针的运算有:

p通过对p中的地址进行解引用,这样找到的是 a , *p其实访问的就是 a 

#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;

	*p = 20;

	return 0;
}

 

 **pp 先通过 *pp找到 p ,然后对 p 进行解引用操作: *p ,那找到的是 a

#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;//p就是指针变量,一级指针变量

	int** pp = &p;//pp就是二级指针

	**pp = 50;

	return 0;
}

 

 

7. 指针数组
 

指针数组是指针还是数组?


答案:是数组。是存放指针的数组


数组我们已经知道整形数组(存放整形的数组)字符数组(存放字符的数组)

int arr1[5];
char arr2[6];

指针数组: 

int* arr3[5];//存放整型指针的数组
char* arr4[6];//存放字符指针的数组

用途:

1.直接存放整形地址

#include<stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	int c = 30;
	int d = 40;
	int e = 50;

	int* arr3[5] = {&a, &b, &c, &d, &e};//存放整型指针的数组
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", *(arr3[i]));
	}

	return 0;
}

2.用一维数组模拟一个二维数组

#include<stdio.h>
int main()
{
	//用一维数组模拟一个二维数组
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	int arr4[] = { 4,5,6,7,8 };

	int* arr[4] = {arr1, arr2, arr3, arr4};
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", *(*(arr+i)+j));
		}
		printf("\n");
	}


	return 0;
}

 结果:

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值