C语言指针进阶(二)

目录

一、字符指针

字符指针的定义

字符指针的使用

二、指针数组

指针数组的定义

指针数组的使用

三、数组指针

数组指针的定义

数组指针的类型

数组指针的使用

&数组名VS数组名

四、数组参数、指针参数

一维数组传参

二维数组传参

一级指针传参

二级指针传参


一、字符指针

字符指针的定义

在指针的类型中我们知道有一种指针类型是字符指针 char*

一般的定义是这样的:

#include<stdio.h>
int main()
{
	char ch = 'w';
	char* p = &ch;
	return 0;
}

将ch的地址放在字符指针变量p里面去了

字符指针的使用

还有一种比较容易出错的使用方式:

#include<stdio.h>
int main()
{
	char* p = "hello world.";//这里是把一个字符串放到p变量里面了吗?
	printf("%s",p);
	return 0;
}

代码char*p="hello world."很容易让大家以为是把一个字符串放到p里面去,但实际上是把"hello world."的首元素地址 ‘h’放到了p变量里面去,通过h的地址就能找到整个字符串了。

 于是就有了这样一个有趣的代码:

#include<stdio.h>
int main()
{
	char str1[] = "hello world.";
	char str2[] = "hello world.";
	char* str3 = "hello world.";
	char* str4 = "hello world.";
	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时,相当于比较数组str1和数组str2的首元素地址,而str1与str2是两个不同的字符数组,创建数组str1和数组str2是会开辟两块不同的空间,它们的首元素地址当然不同。

这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。

注意:常量字符串与普通字符串最大的区别是,常量字符串是不可被修改的字符串,既然不能被修改,那么在内存中没有必要存放两个一模一样的字符串,所以在内存中相同的常量字符串只有一个。

二、指针数组

指针数组的定义

数组我们知道可以存放整型 、字符等。于是顾名思义,指针数组就是存放指针的数组

指针数组的使用

例如:

int* arr1[10]; //整形指针的数组 
char *arr2[4]; //一级字符指针的数组 
char **arr3[5];//二级字符指针的数组 

三、数组指针

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

答案是:指针!

数组指针的定义

我们已经熟悉: 整形指针: int * p; 能够指向整形数据的指针。 浮点型指针: float * p; 能够

指向浮点型数据的指针。 那数组指针 int (*p)[10]; 应该是:能够指向数组的指针

使用时我们只需取出数组的地址,并将其存入数组指针即可,例如这样定义:

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

这里的方括号[ ]的优先级是高于解引用 * 的优先级的,必须要加上。

数组指针的类型

分辨数组指针的类型有一个小窍门,就是先去掉名字,剩下的就是类型,咱直接上图说明:

数组指针的使用

介绍一个打印二维数组的例子,将一个数组的地址传给一个数组指针变量p,通过p来控制打印二维数组

#include<stdio.h>
void print(int(*p)[5], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)//行数
	{
		int j = 0;
		for (j = 0; j < col; j++)//列数
		{
			printf("%d ", *(*(p + i) + j));
		}
		printf("\n");//打印完一行后,换行
	}
}
int main()
{
	int arr[3][5] = { { 1, 2, 3, 4, 5 }, { 2, 3, 4, 5, 6 }, { 3, 4, 5, 6, 7 } };
	print(arr, 3, 5);//传入二维数组名,即二维数组首元素地址,即二维数组第一行的地址
	return 0;
}

&数组名VS数组名

这是一个容易混淆的点:

一般数组名都表示首元素地址,但是两个列外

sizeof(数组名),这里的数组名表示整个数组的大小,单位为byte

&数组名,这里取出的是整个数组的地址

其余的数组名都表示首元素的地址,但有一个特别注意的点,二维数组的数组名表示第一行的地址(看作是一维数组的地址)

四、数组参数、指针参数

试着判断下面的传参是否正确?

一维数组传参

#include <stdio.h>
void test(int arr[])//ok?  传数组名,用数组接收,数组元素个数可省略   正确
{}
void test(int arr[10])//ok?  同上的道理    正确                            
{}
void test(int *arr)//ok?  数组名是首元素地址,用指针接收   正确
{}
void test2(int *arr[20])//ok?  用同样的指针数组接收    正确
{}
void test2(int **arr)//ok?  数组名是首元素地址,而该数组元素是指针,所以地址是int**类型,
                    //      用二级指针接收          正确 
{}
int main()
{
    int arr[10] = {0};
    int *arr2[20] = {0};
    test(arr);
    test2(arr2);
}

总结:1、当数组是整型数组时

           ①数组传参就用数组来接收

void test(int arr[])

           ②数组名就是首元素的地址,我们可以用指针来接收

void test(int *arr)

           2、当数组是指针数组时

           ①数组传参就用数组接收

void test2(int *arr[20])

           ②同理也可以用指针来接收

注意:函数形参部分的一维数组的行数 [ ] 可以省略

二维数组传参

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

总结:①形参给出二维数组的第二维长度

void test(int arr[][5])

           ②形参声明为指向数组的指针 

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

当我们传入的参数为一级指针时,我们可以用一级指针的形参对其进行接收,那么我们可以反过来,当函数形参为一级指针的时候,我们可以传入什么样的参数呢?

 例如:

void test1(int *p) 
{} 
//test1函数能接收什么参数? 
void test2(char* p) 
{} 
//test2函数能接收什么参数? 
#include<stdio.h>
void test(int* p)
{}
int main()
{
	int a = 10;
	test(&a);//可以传入变量的地址
	int* p = &a;
	test(p);//可以传入一级指针
	int arr[10] = { 0 };
	test(arr);//可以传入一维数组名
	//...
	return 0;
}

二级指针传参

#include<stdio.h>
void test(int** p)//二级指针接收
{}
int main()
{
	int a = 10;
	int* pa = &a;
	int** paa = &pa;
	test(paa);//二级指针
	return 0;
}

同样也可以反过来,当函数的参数是二级指针时,我们可以传入什么样的参数呢?

#include<stdio.h>
void test(int** p)
{}
int main()
{
	int a = 10;
	int* pa = &a;
	test(&pa);//可以传入一级指针的地址
	int** paa = &pa;
	test(paa);//可以传入二级指针
	int* arr[10];
	test(arr);//可以传入一级指针数组的数组名

	return 0;
}

感谢博友们的观看!支持一下博主把!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值