目的在于了解指针的基本概念和一些用法

下面是本阶段导图:

C语言指针初级学习笔记_C语言指针

基本概念

int a = 10;
int* p = &a;

指针就是地址,p为指针变量,存放地址的

一个最小的内存单元为一字节

32位机器指针所占内存 4字节

64位机器指针所占内存 8字节

指针类型


1.指针决定访问

指针类型决定了指针解引用访问的字节大小

int* p ;*p能够访问4个字节

char* p;*p能访问1个字节

double* p; *p能够访问8个字节

int main()
{
	int arr[10] = { 0 };
	char* p = arr;//将int类型的数据赋值给char* 型的指针
 
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 1;
	}
 
	return 0;
}

调试后打开内存窗口

C语言指针初级学习笔记_C语言指针_02

可以看到,在int类型的数组中,解引用char*后每次访问的都是1个字节,

但若解引用int*型的指针,则每次访问的都是4个字节即图中的每一行

2.指针决定步长

加上一个整数,指针跳过几个字节

int* p; p+1 -> 4

char* p; p+1 -> 1

double* p; p+1 -> 8

int main()
{
	int a = 10;
	int* pa = &a;
	char* pc = &a;
	
	printf("%p\n",pa);
	printf("%p\n",pa + 1);//地址跳过4个字节
	
	printf("%p\n",pc);
	printf("%p\n",pc + 1);//地址跳过1个字节
    
    return 0;
}

野指针

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

野指针主要出现在以下三种情况:


未初始化

指针变量初始化时未指向地址

int* p;
*p = 20;

越界

指针越界访问,一般出现在数组中,指针变量实际访问的地址,已经超越数组的范围

int main()
{
    int arr[10] = { 0 };
    int* pa = arr;
    int i = 0;
    for (i = 0; i < 11; i++)
    {
        *(pa++) = i;
        //最后一次,指针变量的地址是随机的
    }
 
    return 0;
}

空间释放

 指针指向的地址已经被释放,一般出现在函数中,main方法中,用指针变量指向的函数返回地址已经被释放

int* test()
{
	int a = 10;
	return &a;
}
int main()
{
	int* p = test();
	*p = 5;
 
	return 0;
}

当然,在平时需要我们多加注意,避免造成野指针的现象

指针谨记初始化,若暂不初始化,可以赋值NULL

用指针前检验下,可以用assert函数判断

注意:若指针为空时,无法访问它,且无法用其解引用赋值

指针运算

平常运用指针的过程,会涉及到指针的各种运算,常见的数组类的结合会用到


指针+-整数

这里可以参考上面越界中的代码

 for (i = 0; i < 11; i++)
    {
        *(pa++) = i;
        //最后一次,指针变量的地址是随机的
    }

*pa = i;

pa = pa + 1;


指针- 指针

char ca[5] = {0};
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
printf("%d\n",&arr[0] - &arr[9]);
printf("%d\n",&arr[9] - &ca[0]);//err

大指针-小指针得两个元素的中间数:9

同类型减同类型

注意!占空间36,得出来的结果不是36

指针-指针的应用,这里用它实现了strlen的自拟

int my_strlen(char* str)
{
	char* start = str;
	char* end = str;
	while (end != '\0')
    //while(*end)
	{
		end++;
	}
    //最后一次end会指向'\0'
	return end - start;
}
int main()
{
	char arr[] = "hello world";
	int len = my_strlen(arr);
	printf("%d\n", len);
 
	return 0;
}


比大小 

将指针间地址进行比较

int main()
{
	
	int arr[5] = { 0 };
	int* vp = &arr[0];
	for (vp = &arr[0]; vp < &arr[5];)
	{
		*vp++ = 1;
	}
	//最后一次,vp指向&arr[5],越界野指针
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d\n", *(arr + i));
	}
 
	return 0;
}

在循环中用地址比较

二级指针

指向指针的指针,存放指针的地址。但不仅限于指向指针

int a = 10;
int* pa = &a;
int** ppa = &pa;//二级指针
int*** pppa = &ppa;//三级指针
 
 
**ppa = 20;
printf("%d\n",**ppa);
printf("%d\n",a);

理解:

int* pa 相当于int *pa, *pa表示是指针,指向int类型的数据

二级指针int** ppa 相当于int* *ppa,*ppa表示指针,指向int*类型的数据,同理其他。


当然指针还有许多种类,数组指针、指针数组指针、函数指针、函数指针数组指针等,在初级阶段主要把指针的各个概念理解清楚,后面学习各种指针时就会减少许多混淆,困难。