C语言学习笔记(六)初识指针

发布时间 2023-08-02 15:59:15作者: Arongsec

指针

  • 在32位的机器上,1个指针变量的大小是4个字节,与指针的类型无关
  • 在64位的机器上,1个指针变量的大小是8个字节

指针和指针类型

指针的解引用

指针类型决定了指针进行解引用操作的时候能够访问的空间大小

举例:

int a = 0x11223344;
int* pa = &a;
*pa = 0;//会把a的内容全部改为0,即四个字节全是0,即 00 00 00 00
-------------------------------
char* pc = &a;
*pc = 0;
//只会修改a的内容中的一个字节,即 00 33 22 11
int*   :4个字节
char*   :1个字节
double*    :8个字节

指针+-整数

指针类型决定了加减整数时指针走多远,即指针的步长

举例:

int a = 0x11223344;
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个字节,即一个字符型

举例2

将数组中所有元素改为1

#include<stdio.h>
int main()
{
    int arr[10] = {0};//此时的arr: 0 0 0 0 0 0 0 0 0 0
    int i;
    int* p = arr;//arr即代表数组首地址,不用再使用取地址符号
    for(i=0;i<10;i++)
    {
        *(p+i) = 1; //修改每一个内存空间里的值为1 此时的arr:  1 1 1 1 1 1 1 1 1 1 
    }
    for(i=0;i<10;i++)
    printf("%d ",arr[i]);
    return 0;
}

野指针

概念:指针指向的位置时不可知的

出现原因:

  1. 指针未初始化,默认为随机值
  2. 指针越界访问
int arr[10] = {0};
int* p = arr;
int i = 0;
for(i=0;i<12;i++)
{
	p++;  //p最后会越出arr的范围,则当指针指向的范围超出arr的范围时,P就是野指针
}
  1. 指针指向的内存空间已经被释放
int* test()
{
	int a = 10;
	return &a;
}
int main()
{
	int* p = test();// p确实接收到了test()返回的地址,但是该地址空间在test()返回给main()之后就已经被销毁
	*p = 20;
	return 0;
}

如何规避野指针

  • 要初始化

  • 小心指针越界

  • 若指针指向的空间释放,即不再需要该指针时,就要使指针置NULL,以后不能再访问这个地址。也不再能对这个地址进行修改

  • 使用指针之前检查有效性

指针运算

  • 指针 + - 整数
  • 指针 - 指针
  • 指针的关系运算(比较大小)

指针 + - 整数

int* p;
*p ++=0;

先查看++,再解引用

此处++为后置++,则解引用的还是p,然后再对指针++;

指针 - 指针

得到的结果是两个地址中间的元素个数

指针的关系运算

标准允许指针与该数组最后一个元素的地址比较,但不允许和数组的第一个元素的地址比较

指针和数组

数组名是数组首元素的地址,例外:

  • &arr,即&数组名--数组名表示整个数组---&数组名表示的是整个数组的地址
  • sizeof(arr),即sizeof(数组名),数组名表示的是整个数组,sizeof(数组名)表示的是整个数组的大小
int arr[10] = {0};
printf("%p\n",arr);//A
printf("%p\n",arr+1);//A’
printf("%p\n",&arr[0]);//B
printf("%p\n",&arr[0]+1);//B‘
printf("%p\n",&arr);//C
printf("%p\n",&arr+1);//C’
//A和B意义相同,代表首元素的地址;C代表整个数组的地址
//A'和B'是在原来的基础上加4,C'在原来的基础上加了4*10

通过指针来访问数组

int main()
{
	int arr[10] = {0};
	int* p = arr;
	int i = 0;
	//for(i=0;i<10;i++)
	//{
		//printf("%p=====%p\n",p+i,&arr[i]);//可检验通过指针访问数组和下标访问数组结果相同
	//}
	for(i=0;i<10;i++)
	{
	*(p+i) = i;
	}
	for(i=0;i<10;i++)
	{
		printf("%d ",arr[i]);
      //printf("%d",*(p+i));
	}
	return 0;
}

二级指针

一级指针的地址

类型: int**

int a = 10;
int* pa = &a;
int ** ppa = &pa;//  ppa即为二级指针

二级指针所占内存空间里存储的是一级指针的地址,二级指针所指向的对象的类型是一级指针

实际理解:

int * pa;  // *代表pa是指针,int代表pa指向的对象的类型是int型
int* * ppa;//*代表ppa是指针,int*代表ppa指向的对象的类型是int*
int** * pppa;//……

具体应用

printf("%d",**ppa);//即可以打印a

**ppa = 20;
printf("%d",a);//将a的值改为20然后打印

指针数组

数组指针本质上是指针

指针数组

存放指针的数组

应用

int main()
{	
    int a = 1;
    int b = 2;
    int c = 3;
	int* p[3]={&a,&b,&c};//指针数组
	int i = 0;
	for(I=0;i<3;i++)
	{
	printf("%d ",*(p[i]));
	}
	return 0;
}

其他

  1. 数组作为参数传递给函数时,要么写 A(int* arr); 要么写A(int arr[] );