前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >带你深层了解c语言指针

带你深层了解c语言指针

作者头像
初阶牛
发布2023-02-27 16:11:40
2720
发布2023-02-27 16:11:40
举报
文章被收录于专栏:C语言基础

前言

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯 c语言进阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>:介绍c语言中有关指针更深层的知识. 金句分享: ✨今天所有的混乱与芜杂,努力与精进,✨ ✨都将在进步中变得更加清晰.✨

目录

一、字符指针

我们可以定义一个字符指针,指向一个字符变量,并通过指针来修改这个字符变量.

代码语言:javascript
复制
#include <stdio.h>
int main()
{
	char a = 'x';
	char* p = &a;
	*p = 'y';//通过指针来修改
	printf("%c\n", *p);
	printf("%c", a);
	return 0;
}

那么字符指针还可以怎么用呢?

下面这段代码的运行结果是什么呢?

代码语言:javascript
复制
int main()
{
	char* s1 =  "aabbccdd" ;
	for (int i = 0; i < 3; i++)
	{
		*(s1 + i) = '0';
	}
	printf("%s", s1);
	return 0;
}

答案:

运行错误,原因是"aabbccdd"是常量字符串,它们存放在"常量区"(里面的东西是只读的),是不允许被修改的.

分析:

这段代码是将常量字符串存放进s1指针里面了吗? 显然不可能,想放也放不进去呀. 正确理解是:将该常量字符串的首元素放进了s1,即s1指向该字符串的首元素.

const关键字在后续的库函数模拟中会详细介绍,这里可以理解为被修饰的字符指针指向的内容,使其不能被修改.

使用字符指针打印字符串

代码语言:javascript
复制
int main()
{
	const char* s1 =  "aabbccdd" ;
	printf("%s", s1);
	return 0;
}

如果对上面的代码还是不理解可以看一下,下面的这一道曾经的笔试题:

代码语言:javascript
复制
#include <stdio.h>
int main()
{
	char str1[] = "你好,初阶牛!.";
	char str2[] = "你好,初阶牛!";
	const char* str3 = "你好,初阶牛!";
	const char* str4 = "你好,初阶牛!";
	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 and str2 are not same str3 and str4 are same

原因分析:

str1和str2是两个的字符数组,两个数组是相互独立的,它们在创建时,会各自向内存申请空间,所以地址必然不一样,只不过是在内存中两块不同内存区域存放着相同的内容罢了. 由于字符串常量是不能修改的,在内存中这类常量并没有必要保存两份,他们存储在内存中的常量区(只读型)所以str3和str4指向的是同一块空间.

图解:

在这里插入图片描述
在这里插入图片描述

二、指针数组

1.1 指针数组的定义

指针数组数组还是指针? 答案是数组. 我们知道,

整形数组:存放整形的数组. 字符数组,:存放字符的数组. 浮点型数组:存放浮点型数据的数组,

代码语言:javascript
复制
	int arr1[] = { 1,2,3,4,5 };//整形数组
	char arrr2[] = "abcdef";//字符型数组
	double arr3[] = { 3.4,5.8,1.9 };//浮点型数组

那么用于存放指针数组自然被称为指针数组了. 那么下面哪个是指针数组?

代码语言:javascript
复制
	int* arr1[10];
	int(*arr2)[10];

由于" * “'(星号)的优先级要低于”[ ]"(中括号)

arr1指针数组: arr1先与[10]先结合,故arr1是指针数组 arr2数组指针: 由于括号的优先级更高,所以(*arr2)是指针,指向的对象是数组,故arr2是数组指针.

常见的指针数组:

代码语言:javascript
复制
int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

2.2 使用指针数组模拟二维数组

代码语言:javascript
复制
#include <stdio.h>
int main()
{
	int arr1[4] = { 1,2,3,4 };
	int arr2[4] = { 2,3,4,5 };
	int arr3[4] = { 3,4,5,6 };
	int* arr[3] = { arr1,arr2,arr3 };
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf("%d ", *(arr[i] + j));
		}
		printf("\n");
	}
	return 0;
}

arr1数组,arr2数组,arr3数组在内存中都有自己独立的内存空间, 我们将这三个一维数组的首元素地址放在一个新的指针的数组(arr)中,通过指针数组来访问这三个一维数组,效果就如同二维数组一样,但并不是真正的二维数组. 图解:

在这里插入图片描述
在这里插入图片描述

内存中存储的图:

在这里插入图片描述
在这里插入图片描述

三、数组指针

指向数组指针被称为数组指针.

代码语言:javascript
复制
#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int(*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
	//指针p就是数组指针,指向arr数组
	return 0;
}

数组指针对于一维数组作用并不是很大,数组指针一般用于二维数组. 在二维数组传参时可以使用数组指针接收.

对于初学者,数组指针指针数组经常容易搞混. 试着分析下面这些代码的含义吧!

代码语言:javascript
复制
int arr[5];//1
int *arr1[10];//2
int (*arr2)[10];//3
int (*arr3[10])[5];//4

答案:

1.整形数组:一个包含5个整形元素的整形数组 2.指针数组:数组中包含十个元素,每个元素都是一个整形指针(int*). 3.数组指针:指向一个拥有十个元素的整形指针. 4.数组指针数组:arr3先与[10]结合,说明arr3是一个数组, 其次剩下的int(*)[5]是arr3数组中的元素,显然是数组的每个元素都是一个数组指针.故arr3是存放了10个指向有5个整形元素数组的数组指针数组.

四、一维数组的传参

4.1 整形一维数组传参:

整形一维数组传过来的arr的是数组首元素地址,即一个整形的地址. 整形变量的地址用一级整形指针接收或者同样用数组接收都行.

代码语言:javascript
复制
void test1(int arr[])//使用不指定具体大小的一维数组接收
{}
void test2(int arr[10])//使用具体大小的一维数组接收
{}
void test3(int *arr)//使用指针接收
{}

具体实现:

代码语言:javascript
复制
#include <stdio.h>
//使用同样一维数组接收
void test1(int arr[],int sz)//arr1
{
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
//与test1一样的道理,用指定大小接收当然也没问题
void test2(int arr[5],int sz)//arr1
{}
//使用指针接收
void test3(int* arr,int sz)//arr1
{
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", *(arr+i));//等价于printf("%d ", arr[i]);
	}
	printf("\n");
}

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	test1(arr1,sz);
	test2(arr1,sz);
	test3(arr1,sz);
	return 0;
}

4.2 一维指针数组传参

这三种有一种是错误的.

代码语言:javascript
复制
void test4(int *arr[20])
{}
void test5(int* arr)
{}
void test6(int **arr)
{}

一维指针数组的数组名表示首元素的地址,而首元素是一个整形指针,一级(整形)指针的地址可以用二级指针接收.也可以用相同类型的一维指针数组接收.

代码语言:javascript
复制
#include <stdio.h>
//用整形指针数组接收整形指针数组
void test4(int* arr[3])
{
	for (int i = 0; i < 3; i++)//决定访问整形指针的个数
	{
		for (int j = 0; j < 4; j++)//决定使用整形指针向后访问整形元素的个数
		{
			printf("%d ", *(arr[i] + j));
		///等价于printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}
//错误,不能使用
void test5(int* arr)
{

}
//用二级指针接收一维指针数组
void test6(int** arr)
{
	for (int i = 0; i < 3; i++)//决定访问整形指针的个数
	{
		for (int j = 0; j < 4; j++)//决定使用整形指针向后访问整形元素的个数
		{
			printf("%d ", *(*(arr+i) + j));//这种一般不好理解
			//等价于	printf("%d ", *(arr[i] + j));
			//等价于	printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr1[4] = { 1,2,3,4 };
	int arr2[4] = { 2,3,4,5 };
	int arr3[4] = { 3,4,5,6 };
	int* arr[3] = { arr1,arr2,arr3 };
	test4(arr);
	test5(arr);
	test6(arr);
}

五、二维数组传参

给定一个二维整形数组: 二维数组的数组名代表首元素地址,即第一行的地址(int*[ ]);

代码语言:javascript
复制
int arr[2][4] = { {1,2,3,4 },{5,6,7,8} };

下面七种传参方式,哪些是正确的.

代码语言:javascript
复制
void test1(int arr[2][4])
void test2(int arr[][])
void test3(int arr[][4])
void test4(int *arr)
void test5(int* arr[4])
void test6(int (*arr)[4])
void test7(int **arr)

正确传参方式:test1()、test3()和test6()

代码语言:javascript
复制
#include <stdio.h>
void test1(int arr[2][4])
{
	int i = 0, j = 0;
	printf("test1\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}
void test3(int arr[][4])
{
	int i = 0, j = 0;
	printf("test2\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}
void test6(int(*arr)[4])//ok?
{
	int i = 0, j = 0;
	printf("test3\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}
int main()
{
	int arr[2][4] = { {1,2,3,4 },{5,6,7,8} };
	test1(arr);
	test3(arr);
	test6(arr);
}

二级指针作为参数

二级指针可以接收一级指针的地址.

代码语言:javascript
复制
#include <stdio.h>
void print1(int** aa)
{
	printf("%d\n", **aa);
}
void print2(char** pp)
{
	printf("%c\n", **pp);
}
int main()
{
	int a = 5;
	int* aa = &a;
	char* p = "abcdef";
	char** pp = &p;
	print1(&aa);
	print2(&p);
	print2(pp);
	return 0;
}

指针进阶的内容比较多,本篇先讲到这里. 最后希望这篇文章对大家有些帮助. 感觉支持!!!💗💗💗

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-02-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • 目录
    • 一、字符指针
    • 二、指针数组
      • 1.1 指针数组的定义
        • 2.2 使用指针数组模拟二维数组
        • 三、数组指针
        • 四、一维数组的传参
          • 4.1 整形一维数组传参:
            • 4.2 一维指针数组传参
            • 五、二维数组传参
              • 二级指针作为参数
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档