指针的进阶(1)

指针的回顾

在C语言中,指针是一个变量,与其他数据不同的是,它的作用是用来存储其它变量的内存地址。指针可以指向不同类型的数据,包括整数、浮点数
、字符、数组等。通过使用指针,我们可以直接访问和修改存储在内存中的数据,而不需要进行复制或者传递大量的数据。
这是指针的大概情况,下面就要对指针进一步研究。

字符指针

对于字符来说,我们可以用char类型来创建变量,那么就有char*类型的指针,通常我们称之为字符指针。
先看以下代码:

int main()
{
    
    
 char ch = 'w';
 char *pc = &ch;
 *pc = 'w';
 return 0;
}
创建一个字符变量ch,字符指针pc指向ch的地址,对pc解引用就是'w'。

这是常规的用法,但在大多数情况下,以下情况更加普遍使用:

int main()
{
    
    
 const char* pstr = "hello cc.";
 printf("%s\n", pstr);
 return 0;
}
在这里,打印出来的就是“hello cc",但pstr存的是字符串的首元素地址
,也就是说,对ptsr解引用,得到的是'h'。

在这里插入图片描述
在这里,会发现我在指针pstr加入了const,这是因为字符串的地址本来就不可改变,加上const,增加程序的可读性和维护性。看下面例子:

#include <stdio.h>
int main()
{
    
    
 char str1[] = "hello cc.";
 char str2[] = "hello cc.";
 const char *str3 = "hello cc.";
 const char *str4 = "hello cc.";
 if(str1 ==str2)
 printf("str1 and str2 are same\n");
 else
 printf("str1 and str2 are not same\n");
 
 if(str3 ==str4)
 printf("str3 and str4 are same\n");
 else
 printf("str3 and str4 are not same\n");
 
 return 0;
}

结果:
在这里插入图片描述
对于str1和str2,它们是字符数组,对于数组来说,会在内存中开辟空间,而str1和str2是两个不同的字符数组,虽然它们的内容相同,但开辟的空间肯定是不一样的,而数组名一般又是指首元素的地址,所以各不相同;对于str3和str4,它们是字符指针,相当与常量字符串自己开辟了空间,然后两个指针都会指向内容相同的字符串首元素
在这里插入图片描述

指针数组

顾名思义,它是一个数组,只是每个数组里面存放的是指针;
在这里插入图片描述
我们可以用指针数组实现二维数组

int main()
{
    
    
	int arr1[] = {
    
     1,2,3,4,5 };//arr1 - int*
	int arr2[] = {
    
     2,3,4,5,6 };
	int arr3[] = {
    
     3,4,5,6,7 };

	//指针数组
	int* arr[3] = {
    
     arr1, arr2, arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
    
    
		int j = 0;
		for (j = 0; j < 5; j++)
		{
    
    
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

在这里插入图片描述
对于一维数组来说,本质上就是一维指针,也就是arr1 类型为int*.

数组指针

指针的定义

数组指针,是一个指针,指向数组的指针。

int *p1[10];//指针数组
int (*p2)[10];//数组指针

在这里插入图片描述
这里要注意:[]的优先级要高于号的,所以必须加上()来保证p先和结合。

&数组名VS数组名

int arr[10];

我们知道,arr是指首元素地址,&arr指的是整个数组的地址;

int main()
{
    
    
	int arr[10] = {
    
     0 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
 	printf("%p\n",&arr);
	return 0;
}

在这里插入图片描述
上面虽然的地址都是一样,这是因为刚好都指向了首元素地址
在这里插入图片描述

int main()
{
    
    
	int arr[10] = {
    
     0 };
	printf("%p\n", arr);//
	printf("%p\n", arr+1);//

	printf("%p\n", &arr[0]);//
	printf("%p\n", &arr[0]+1);//

	printf("%p\n", &arr);//
	printf("%p\n", &arr+1);//

	
	return 0;
}

在这里插入图片描述

但我们把16进制转换为10进制后&arr+1就增加了40个bit,但arr+1相对于arr只增加了4bit
在这里插入图片描述

根据上面的代码我们发现,其实&arr和arr,虽然值是一样的,但是意义应该不一样的。
实际上: &arr 表示的是数组的地址,而不是数组首元素的地址.

数组指针的使用

直接看以下代码:

#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
    
    
 	int i = 0;
	 for(i=0; i<row; i++)
 	{
    
    
	 for(j=0; j<col; j++)
	 {
    
    
	 printf("%d ", arr[i][j]);
	 }
	 printf("\n");
 }
}
void print_arr2(int (*arr)[5], int row, int col)
{
    
    
 int i = 0;
 for(i=0; i<row; i++)
 {
    
    
 	for(j=0; j<col; j++)
 	{
    
    
	 printf("%d ", arr[i][j]);
 	}
	 printf("\n");
 }
}
int main()
{
    
    
	 int arr[3][5] = {
    
    1,2,3,4,5,6,7,8,9,10};
	 print_arr1(arr, 3, 5);
 
	 print_arr2(arr, 3, 5);
	 return 0;
}

在这里插入图片描述
对于一维数组来说,数组名表示首元素地址,而二维数组中,首元素表示的是第一行的地址,所以把数组指针看作是二维数组中,指向一维数组的指针。也就是所,二维数组可以由数组指针来表示。

数组参数、指针参数

一维数组传参

#include <stdio.h>
void test(int arr[])
{
    
    }
void test(int arr[10])
{
    
    }
void test(int *arr)
{
    
    }
void test2(int *arr[20])
{
    
    }
void test2(int **arr)
{
    
    }
int main()
{
    
    
 int arr[10] = {
    
    0};
 int *arr2[20] = {
    
    0};
 test(arr);
 test2(arr2);
}

对于以上所有test函数来说,所有形式参数都是可以接收到实参的;数组本质来说就是指针,所以可由指针来接收;而指针数组来说,就要用二维指针来接收。

二维数组传参

void test(int arr[3][5])
{
    
    }
void test(int arr[][5])
{
    
    }
//对于二维数组来说,行的数字可以省略,列的数字不能省略
void test(int *arr)
{
    
    }
void test(int (*arr)[5])
{
    
    }
//数组指针是可以的,但对于指针数组来说,数组中包含的是指针,虽然说
//数组本质就是指针,但是由于数组的限制,指针的地址可能会出现连续的
//状态,无法确定一行中有多少列,故不可使用。

一级指针传参

#include <stdio.h>
void print(int *p, int sz)
{
    
    
 int i = 0;
 for(i=0; i<sz; i++)
 {
    
    
 printf("%d\n", *(p+i));}
}
int main()
{
    
    
 int arr[10] = {
    
    1,2,3,4,5,6,7,8,9};
 int *p = arr;
 int sz = sizeof(arr)/sizeof(arr[0]);
 //一级指针p,传给函数
 print(p, sz);
 return 0;
}

对于数组来说,元素的地址是连续存在的,所以可以用指针叠加的方式进行循环遍历。

二级指针传参

#include <stdio.h>
void test(int** ptr)
{
    
    
printf("num = %d\n", **ptr); 
}
int main()
{
    
    
 int n = 10;
 int*p = &n;
 int **pp = &p;
 test(pp);
 test(&p);
 return 0;
 }

num=10
num=10

对于实参来说,只要是一级指针的地址,就可以传参,而函数中的形参一般只用二级指针接收即可。

总的来说,对于数组传参,形参部分可以是指针,也可以是数组;
而对于指针传参,实参部分只要是地址,都可以当作实参,形参只用指针来接收。

猜你喜欢

转载自blog.csdn.net/m0_74068921/article/details/131587370