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

news/2025/2/7 6:53:51/

在这里插入图片描述

大家好啊,我是小象٩(๑òωó๑)۶
我的博客:Xiao Xiangζั͡ޓއއ

很高兴见到大家,希望能够和大家一起交流学习,共同进步
在这里插入图片描述
今天我们继续来学习指针数组,指针数组模拟二维数组字符指针变量…

目录

  • 一、指针数组
    • 1 指针数组的定义
  • 二、指针数组模拟二维数组
  • 三、字符指针变量
  • 四、结尾

一、指针数组

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

指针数组是指针还是数组?
我们类比一下,整型数组,是存放整型的数组,字符数组是存放字符的数组。
那指针数组呢?是存放指针的数组。

1 指针数组的定义

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

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

示例:

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

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

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

#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 函数将每个元素打印出来,并在每行结束时换行。

parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型一维数组,parr[i][j]就是整型一维数组中的元素。
上述的代码模拟出二维数组的效果,实际上并非完全是二维数组,因为每一行并非是连续的。

三、字符指针变量

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

字符指针与字符数组的区别
存储方式
字符数组在内存中是连续存储的,而字符指针只是存储了一个地址。
可修改性
字符数组中的元素可以修改,而指向字符串常量的字符指针不能修改其所指向的内容。
生命周期
字符数组的生命周期取决于其定义的位置,而字符指针可以通过动态内存分配来灵活控制生命周期。

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

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

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

上面代码的意思是把一个常量字符串的首字符 h 的地址存放到指针变量 pstr 中。
《指offer》中收录了⼀道和字符串相关的笔试题,我们⼀起来学习一下:

#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");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("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 函数,且字符指针指向的常量字符串不可修改,如需可修改字符串,应使用字符数组。

下面是这两节所写代码:

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* arrvoid 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的地址赋给pprintf("%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");//1elseprintf("str1 and str2 are not same\n");//2if (str3 == str4)printf("str3 and str4 are same\n");//3elseprintf("str3 and str4 are not same\n");//4return 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");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}

四、结尾

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


http://www.ppmy.cn/news/1570008.html

相关文章

简述mysql 主从复制原理及其工作过程,配置一主两从并验证。

MySQL 主从复制工作过程 1、二进制日志记录&#xff08;Binary Logging&#xff09;&#xff1a; 主服务器开启二进制日志记录功能&#xff0c;将所有更改数据的操作&#xff08;如 INSERT、UPDATE、DELETE&#xff09;记录到二进制日志文件中。 2、日志传输&#xff08;Log…

nginx伪静态配置解释和Nginx 常见的配置

文章目录 禁止访问 runtime 和 application 目录rewrite 对 URL 进行重写或重定向301重定向root 静态资源路径处理alias 路径映射try_files 伪静态规则Nginx 配置有许多其他常见的场景和使用方式 1. **基本的反向代理配置**2. **负载均衡配置**3. **限制访问&#xff08;IP 限…

机器学习9-卷积和卷积核2

机器学习9-卷积和卷积核2 卷积与边缘提取边缘的种类边缘检测图像求导解析示例 图像求导公式&#xff1a;解析总结 图像梯度噪声的影响 边缘检测目标非极大值抑制总结 卷积与边缘提取 边缘&#xff1a;图像中亮度明显而急剧变化的点 为什么要研究边缘&#xff1f; 编码图像中…

计算机组成原理——存储系统(四)

当晨曦的第一缕光线划破夜空&#xff0c;那是宇宙给奋斗者的信号——光明属于那些在黑暗中依旧寻找希望的人。在这条通往梦想的道路上&#xff0c;每一步都充满挑战&#xff0c;但正是这些挑战定义了你的坚韧与不屈。不要满足于现状&#xff0c;因为你的潜力远超想象&#xff1…

十二、Docker Compose 部署 SpringCloudAlibaba 微服务

一、部署基础服务 0、项目部署结构 项目目录结构如下: /home/zhzl_hebei/ ├── docker-compose.yml └── geochance-auth/└── Dockerfile└── geochance-auth.jar └── geochance-system/└── Dockerfile└── geochance-system.jar └── geochance-gateway/…

C++Primer 赋值运算符

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

自动驾驶---两轮自行车的自主导航

1 背景 无人驾驶汽车最早出现在DARPA的比赛中&#xff0c;从那个时刻开始&#xff0c;逐渐引起全球学者的注意&#xff0c;于是从上个世纪开始各大高校院所开始了无人汽车的研发。直到这两年&#xff0c;无人驾驶汽车才开始走进寻常百姓家&#xff0c;虽然目前市面上的乘用车还…

C语言数据结构编程练习-排序算法

1、冒泡排序 思路&#xff1a;比较相邻的两个数&#xff0c;左边大于右边交换一趟排下来最大的在右边时间复杂度&#xff1a;O(n2) //冒泡排序 从小到大的顺序排列 //思路&#xff1a;比较相邻的两个数&#xff0c;左边大于右边交换一趟排下来最大的在右边 void bubbleSort(i…