C语言进阶——指针(一)

目录

一.   字符指针

二.   指针数组

三.   数组指针

四.   数组参数、指针参数

1.一维数组传参

2.二维数组传参

3.一级指针传参

4.二级指针传参


一.   字符指针

在之前,我们就了解到过字符指针

int main()
{
    char a='W';//字符变量
    char* pa=&a;//字符指针
    *pa='w';
    return 0;
}

而除此之外,字符指针还有一种使用方法

char* pstr="abcdef";

我们可以看到,我们似乎是将一串字符串赋给了字符指针pstr

而事实上,我们是将abcdef这个常量字符串的首字符的地址放在了pstr中

而abcdef作为一个常量字符串,本身应该不能被改变,因此我们可以使用const来修饰pstr

const char* pstr="abcdef";

实例

#include <stdio.h>
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    const char *str3 = "hello bit.";
    const char *str4 = "hello bit.";
    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都是取静态区中abcdef的首元素地址,所以地址相同。



二.   指针数组

无非就是存储指针的数组。

而在上面的字符指针中,我们可以赋予字符串的首地址,因此,指针数组也可以这样操作

char* arr[3]={"abcd","bcde","cdef"};

同样,数组名是该数组首元素的地址,因此,我们也可以将数组名作为指针存放在指针数组中

int nums1[]={1,2,3,4};
int nums2[]={2,3,4,5};
int nums3[]={3,4,5,6};
int nums4[]={4,5,6,7};
int* nums[]={nums1,nums2,nums3,nums4};


三.   数组指针

同样,数组指针也是存放数组地址的指针

在考虑数组指针前,我们可以先来了解一下数组名和&数组名的区别

首先,我们知道,数组名是该数组首元素的地址

那么,将数组名取地址得到的也必然是一个地址,那么这个地址代表的是什么呢?

在我们直接打印两个地址时, 可以发现是相同的。但指针还存在步长,我们可以从步长来了解两者之间的差别

可以看到,这时两者出现了差别,nums与nums+1之间差距4个字节, 也就是int类型的大小,而&nums与&nums+1之间差距16个字节,也就是4个int类型所占的大小,当然也就是整个数组所占内存大小。

因此我们可以得知,不同于数组名所代表的的首元素地址,&数组名所代表的整个数组的地址

在我们了解到数组名与&数组名的差别后,我们也就可以来实现数组指针

数组指针理所应当存储整个数组的地址,因此我们要选择&数组名,同时(以整形数组为例)数组指针的类型应该为int (*) [10],其中int 指的是数组中的元素类型,而*表示这是一个指针类型,而[10]则代表数组的大小为10;因此我们就可以实现数组指针

int nums[4]={1,2,3,4};
int(*p)[4]=&nums;
printf("%d", (*p)[0]);
printf("%d",nums[0]);//效果相同

而在使用中,我们很少将一维数组的地址存储为数组指针,因为比较的鸡肋,我们可以在二维数组中使用到它

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

二维数组在传参时,数组名同样是首元素的地址,而二维数组首元素的地址指的是第一行的地址
,而第一行其实是一个一维数组,因此可以使用数组指针来接受



四.   数组参数、指针参数

1.一维数组传参

#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);
}

一维数组传参其实都比较简单,我们可以知道,上面几种传参方法都是正确的


2.二维数组传参

void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}


void test(int* arr)//ok?
{}
void test(int* arr[5])//ok?
{}
void test(int(*arr)[5])//ok?
{}
void test(int** arr)//ok?
{}

int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}

首先我们先看一下前三种传参方式,由于二维数组的行可以忽略,而列不能忽略,我们可以知道第一种和第三种是正确的,而第二种是违规的

而后面四种则和指针相关。首先我们在上面提到过,二维数组的数组名代表二维数组第一行的地址,而第一种写法中使用整形指针显然不行。                                                                                而第二种的参数为一个指针数组,也不可以。                                                                                第三种写法在我们上面提到过类似的,是一个数组指针,因此可以。                                                最后一种写法作为一个二级整形指针,固然也不可以

而经常刷题的老铁会发现一个问题

类似于这样的题目,在二维数组传参时使用的是就是char** board,而这种方法我们在前面已经被否定了,这又是为什么呢?

 这是因为,在leetcode中,所传入的“二维数组”其实是由一维数组模拟而来的

char** board = (char**)malloc(sizeof(char*) * m);
for (int i = 0; i < m; i++)
{
	board[i] = (char*)malloc(sizeof(char) * n);
}

而malloc我们会在后面的动态内存管理中学到,这里就不过度展开


3.一级指针传参

#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]);
	print(p, sz);
	return 0;
}

指针的传参实现是比较简单的,我们主要考虑函数参数部分为指针时能接受什么参数

一级指针所能接受的参数我们目前常见的有数组名、&变量、指针变量


4.二级指针传参

#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;
}

同样,二级指针所能接受的参数有二级指针变量、&一级指针变量、指针数组的数组名等。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

finish_speech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值