程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图<5>

大家好啊,我是小象٩(๑òωó๑)۶
我的博客:Xiao Xiangζั͡ޓއއ
很高兴见到大家,希望能够和大家一起交流学习,共同进步

今天我们继续来学习指针数组,指针数组模拟二维数组字符指针变量...

目录

一、指针数组

C语言中的指针数组是一种特殊的数组,其元素都是指针类型。每个元素可以指向不同类型或相同类型的数据,常用于管理多个地址(如字符串数组、动态内存分配等)。

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

我们类比一下,整型数组,是存放整型的数组,字符数组是存放字符的数组。

那指针数组呢?是存放指针的数组。

1 指针数组的定义

语法:数据类型 *数组名数组长度;

特点:数组的每个元素都是一个指针,需单独初始化后才能使用。

示例:

c 复制代码
int *ptr_arr[5];  // 定义一个包含5个整型指针的数组
char *str_arr[3]; // 定义一个包含3个字符指针的数组

指针数组的每个元素是地址,又可以指向一块区域。

二、指针数组模拟二维数组

c 复制代码
#include <stdio.h>
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	//数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中
	int* parr[3] = { arr1, arr2, arr3 };
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d ", parr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

代码分析

数组定义:定义了三个一维整型数组 arr1、arr2 和 arr3,每个数组都包含 5 个整数元素。

指针数组定义与初始化:定义了一个指针数组 parr,它包含 3 个元素,每个元素都是 int* 类型的指针。将 arr1、arr2 和 arr3 的首地址分别赋值给 parr 的三个元素。

嵌套循环遍历:使用嵌套的 for 循环来遍历 parr 指针数组中的每个元素,并访问它们所指向的数组中的每个元素。外层循环控制访问哪个数组,内层循环控制访问数组中的每个元素。 输出结果:使用printf 函数将每个元素打印出来,并在每行结束时换行。

parri是访问parr数组的元素,parri找到的数组元素指向了整型一维数组,parrij就是整型一维数组中的元素。

上述的代码模拟出二维数组的效果,实际上并非完全是二维数组,因为每一行并非是连续的。

三、字符指针变量

在 C 语言中,字符指针变量是一种特殊的指针类型,它主要用于指向字符数据,在处理字符串等操作中有着广泛的应用。

字符指针与字符数组的区别

存储方式

字符数组在内存中是连续存储的,而字符指针只是存储了一个地址。

可修改性

字符数组中的元素可以修改,而指向字符串常量的字符指针不能修改其所指向的内容。

生命周期

字符数组的生命周期取决于其定义的位置,而字符指针可以通过动态内存分配来灵活控制生命周期。

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

⼀般使用:

c 复制代码
int main()
{
	char ch = 'w';
	char* pc = &ch;
	*pc = 'w';
	return 0;
}

还有⼀种使用方式如下:

c 复制代码
int main()
{
	const char* pstr = "hello bit.";//这⾥是把⼀个字符串放到pstr指针变量⾥了吗?
	printf("%s\n", pstr);
	return 0;
}

代码 const char* pstr = "hello bit."; 特别容易让同学以为是把字符串 hello bit 放到字符指针 pstr 里了,但是本质是把字符串 hello bit. 首字符的地址放到了pstr中。

上面代码的意思是把一个常量字符串的首字符 h 的地址存放到指针变量 pstr 中。

《指offer》中收录了⼀道和字符串相关的笔试题,我们⼀起来学习一下:

c 复制代码
#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;
}

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

代码定义了两个字符数组 str1 和 str2,它们虽内容均为 "hello bit.",但在内存中各自占据独立空间;同时定义了两个字符指针

str3 和 str4,由于相同字符串字面量通常只在内存中存储一份,所以二者指向同一内存地址。代码使用 == 对指针(数组名本质为指针)进行比较,此操作实际比较的是地址,因此 str1 与 str2 比较结果为不同,str3 与 str4 比较结果为相同。需注意,若要比较字符串内容,应使用 strcmp 函数,且字符指针指向的常量字符串不可修改,如需可修改字符串,应使用字符数组。

下面是这两节所写代码:

c 复制代码
int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	//int* p = &arr[0];
	//int* p = arr;//数组名arr就是数组首元素(第一个元素)的地址
	printf("&arr[0] = %p\n", &arr[0]);
	printf("arr     = %p\n", arr);

	return 0;
}


int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%zd\n", sizeof(arr));//40个字节

	return 0;
}


int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	//int* p = &arr[0];
	//int* p = arr;//数组名arr就是数组首元素(第一个元素)的地址
	printf("&arr[0]   = %p\n", &arr[0]);//首元素的地址
	printf("&arr[0]+1 = %p\n", &arr[0]+1);

	printf("arr       = %p\n", arr);    //首元素的地址
	printf("arr+1     = %p\n", arr+1);    

	printf("&arr      = %p\n", &arr);     //数组的地址
	printf("&ar+1     = %p\n", &arr+1);   


	return 0;
}


int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//打印数组的内容,使用指针
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//打印数组的内容,使用指针
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *p);
		p++;//p = p+1
	}
	return 0;
}

int main()
{
	int arr[10] = { 0 };
	//打印数组的内容,使用指针
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	//输入数组内容
	for (i = 0; i < sz; i++)
	{
		scanf("%d", p+i);
	}
	//输出数组的内容
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *p);
		p++;//p = p+1
	}
	return 0;
}

int main()
{
	int arr[10] = { 0 };
	//打印数组的内容,使用指针
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	//输入数组内容
	for (i = 0; i < sz; i++)
	{
		scanf("%d", p);
		p++;
	}
	//输出数组的内容
	p = arr;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *p);
		p++;//p = p+1
	}
	return 0;
}


int main()
{
	int arr[10] = { 0 };
	//打印数组的内容,使用指针
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	//输出数组的内容
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p+i));
	}
	return 0;
}


2+3 -->3+2
arr[i] --> *(arr+i)
i[arr] --> *(i+arr)

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//打印数组的内容,使用指针
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	//输出数组的内容
	//arr[i] --> *(arr+i)
	//
	//[]就是一个操作符而已
	//
	for (i = 0; i < sz; i++)
	{
		//printf("%d ", i[arr]);//
		//printf("%d ", i[p]);//?
		//printf("%d ", *(i + p));
		//printf("%d ", p[i]);//*(p+i) == p[i]
		//*(p+i) == p[i]  --->  *(i+p) == i[p]
		//printf("%d ", *(p+i));
	}
	return 0;
}


void print_arr(int arr[], int sz)
{
	int i = 0;
	for(i=0; i<sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//写一个函数,打印数组的内容
	int sz = sizeof(arr) / sizeof(arr[0]);
	print_arr(arr, sz);

	return 0;
}



int* arr

void print_arr(int *arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);//arr[i] --> *(arr+i)
	}
	printf("\n");
}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//写一个函数,打印数组的内容
	//数组在传参的时候,不会将整个数组传递过去
	//
	print_arr(arr, sz);//arr数组名表示就是数组首元素的地址,所以这里传递过去的就是数组首元素的地址

	return 0;
}

数组传参的时候,传递是数组首元素的地址
1.函数的形参可以写成数组,也可以写成指针 
2.所以在函数内没办法计算数组的元素个数
3.所以形参的数组和实参的数字是同一个数组 


void bubble_sort(int arr[], int sz)
{
	int i = 0;
	//趟数
	for(i = 0; i < sz-1; i++)
	{
		int flag = 0;//假设已经有序
		//处理一趟排序的过程 - 处理多少对数据
		for (int j = 0; j < sz-1-i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				flag = 1;
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
		if (flag == 0)
		{
			break;
		}
	}
}

void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}


int main()
{
	//3,1,7,5,8,9,0,2,4,6
	//排序 - 排成升序
	//int arr[] = {9,8,7,6,5,4,3,2,1,0};
	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	//冒泡排序
	int sz = sizeof(arr) / sizeof(arr[0]);
	print_arr(arr, sz);
	bubble_sort(arr, sz);
	print_arr(arr, sz);

	return 0;
}





int main()
{
	int a = 10;
	int* p = &a;//一级指针变量
	int** pp = &p;//pp就叫二级指针

	printf("%d\n", **pp);//*(*pp)

	return 0;
}





int main()
{
	int a = 10;
	int b = 20;
	int c = 30;
	int* arr[3] = { &a, &b, &c };//arr 是存放指针的数组 - 指针数组
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%d ", *(arr[i]));
	}
	return 0;
}





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

	//        int*  int*  int*  
	int* arr[3] = {arr1, arr2, arr3};
	//arr就是指针数组
	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;
}




int main()
{
	//char ch = 'w';
	//char* p = &ch;

	//char arr[10] = "abcdef";
	//char* p = arr;
	//printf("%s\n", arr);
	//printf("%s\n", p);

	const char* p = "abcdef";//这次赋值是将字符串首字符a的地址赋给p
	printf("%c\n", *p);
	//*p = 'w';//程序会崩溃
	return 0;
}



#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");//1
    else
        printf("str1 and str2 are not same\n");//2

    if (str3 == str4)
        printf("str3 and str4 are same\n");//3
    else
        printf("str3 and str4 are not same\n");//4

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

	
	int(*p)[5] = &arr;//取出数组的地址
	//p是数组指针变量
	//p就应该是能够存放数组的地址的一种指针变量 - 数组指针变量

	return 0;
}



int main()
{
	/*char arr[8];
	char (*pc)[8] = &arr;*/

	char* arr[7];
	char* (*pc)[7] = &arr;//pc数组指针变量

	return 0;
}



int main()
{
	char ch = 'w';
	char* pc = &ch;
	*pc = 'w';
	return 0;
}


int main()
{
	const char* pstr = "hello bit.";//这⾥是把⼀个字符串放到pstr指针变量⾥了吗?
	printf("%s\n", pstr);
	return 0;
}

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

四、结尾

这一课的内容就到这里了,下节课继续学习指针的其他一些知识
如果内容有什么问题的话欢迎指正,有什么问题也可以问我!

相关推荐
Scott9999HH8 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社9 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海9 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖10 小时前
JDK 26 新特性详解
java·开发语言
马优晨10 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区12 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大13 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai13 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜13 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa13 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio