当前位置: 首页 > news >正文

C 语言学习笔记(指针3)

内容提要

  • 指针
    • 数组指针
    • 指针数组
    • 字符数组和字符指针

指针

数组指针与指针数组

数组指针
指针和数组中符号优先级
() > [] > *
通过指针引用二维数组
表现形式含义地址/值
a二维数组名,指向一维数组啊a[0]2000
a[0], *(a+0), *a0行0列元素地址2000
a+1, &a[1]1行首地址2008
a[1], *(a+1 )1行0列元素a[1 ] [0]的地址2008
a[1]+2, *(a+1)+2, &a[1] [2]1行2列元素a[1] [2]的地址2012
*(a[1]+2), *( *(a + 1)+2), a[1] [2]1行2列元素a[1] [2]的值元素值为13

注意:二维数组中,数组整体的地址值 = 数组中0行元素的地址值 = 数组中0行0列的地址值

在这里插入图片描述

案例

案例1

  • 需求:用指向元素的指针变脸输出二维数组的值
  • 代码:
int main()
{// 定义一个二维数组int arr[3][4] = {10,20,30,40,100,200,300,400,1000,2000,3000,4000};// 定义一个指针变量,用来接收二维数组的元素int *p = arr[0]; // 指向10的位置// 获取元素个数int len = (sizeof(arr)/sizeof(arr[0]) * (sizeof(arr[0])/sizeof(arr[0][0]));//遍历数组// 通过指针变量访问二维数组,只需要一层for循环for (; p < arr[0] + len; p++){// 每四个换行if ((p - arr[0]) % 4 == 0 && p != arr[0]) printf("\n");printf("%-6d", *p);}printf("\n");return 0}

案例2:

  • 需求:数组指针,输出二维数组任一行任一列元素的值
  • 代码:
int main()
{//定义一个二维数组int arr[3][4] = {1,3,5,7,11,33,44,77,111,333,555,777};//创建一个数组指针指向二维数组int (*p)[4] = arr; // 二维数组中的第一个元素就是首行// 创建两个变量,接收控制台输入的行和列int row, col;printf("请输入行号和列号:\n");scanf("%d,%d", &row, &col);printf("arr[%d][%d]=%d,%d,%d,%d\n", row, col, *(*(p+row)+col), (*(p+row))[col],*(p[row]+col), p[row][col]);return 0;
}
指针数组

定义:指针数组是一个数组,数组中的每一个元素都是一个指针。

特点

  • 先有指针,后有数组
  • 指针数组的本质是一个数组,只是数组中元素类型是指针。

语法:

数组类型 *数组名 [容量];

案例:

int main()
{//定义三个变量int a = 10, b = 20, c = 30;//定义指针数组,指针数组是用来存储指针的int *arr[3] = {&a,&b,&c};//获取数组大小int len = sizeof(arr) / sizeof(arr(0));//遍历数组for (int i = 0; i < len; i++){printf("%-3d", *arr[i]); // arr先和[]结合取出地址,地址再跟左侧*结合,解引用出地址对应空间的数据}printf("\n");return 0; 
}

建议:我们一般使用指针数组处理字符串。

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

在这里插入图片描述

字符数组和字符指针

字符串的实现

在C语言中,表示一个字符串有以下两种方式

①数组形式:用字符数组存放一个字符串

②指针形式:用字符指针存放一个字符串

案例
#include <stdio.h>
/**
*方式1:使用字符数组实现字符串
**/
void str_test1()
{// 定义一个伪字符串char str[]= “F LOVE YOU";printf("%s\n",str);
}
/**
*方式2:使用字符指针实现字符串
**/
void str_test2()
{// 定义一个伪字符串char *str ='I LOVE YOU";printf("%s\n",str);
}
int main(int argc,char *argv[])
{str_test10;str_test20);return 0;
}

注意:字符数组和字符指针变量都是能实现字符串的存储和运算。(字符指针 —> 字符类型的指针变量)

字符数组和字符指针的联系
概念
  • 字符数组由元素组成,每个元素存放一个字符;而字符指针(变量)中存放的是地址(可以作为函数参数)
  • 只能对字符数组中的各个元素赋值,而不能用赋值语句对整个字符数组赋值。
char arr[3] = {}; // {'\0'}
arr[2] = 'A';    // 正确,对字符数组中的元素赋值arr = {'E', 'D', 'F'}; // 错误,对整个数组赋值(可以理解为数组名就是一个常量,一旦创建就无法改变))
  • 字符数组名虽然代表地址,但数组名的值不能改变,因为数组名是常量
  • 对于字符串中字符的存取,可以用下标法,也可以用指针法。
案例
int main()
{// 使用两种方式创建字符串char str1[] = "你好, 双哥哥!";char *str2 = "你好, 豪哥哥!"; // 0x11// 赋值测试// str1 = "你好,强哥哥!"; //错误,数组一旦创建就无法改变其值。str2 = "你好,帅哥哥!"; // 0x12//打印测试printf("%s,%s\n", str1,str2);// 测试从控制台获取一个字符串char *str; //此时默认值是NULL,NULL对应的空间地址0x00000000,这块空间拒绝访问printf("请输入一个字符串:\n");scanf("%s", str);printf("输出-%s\n", str); // 输出NULL// 注意:从控制台接收一个字符串只能用字符数组char a[] = "I LOVE YOU!";char *b = "I LOVE YOU!";printf("%c,%c\n%c, %c\n%s,%s\n",a[2],*(a+2),b[2],*(b+2),a+2,b+2);// L,L,L,L,LOVE YOU,LOVE YOUreturn 0;
}
字符串作为形式参数
定义
  • 实参与形参都可以是字符数组
void fun(char str[], int len){...}
void main()
{char str[] = "hello";int len = sizeof(str) / sizeof(str[0]);fun(str, len);
}
  • 实参用字符数组,形参用字符指针
void fun(char *str, int len){...}
void main()
{char str[] = "hello";int len = sizeof(str) / sizeof(str[0]);fun(str, len);
}
  • 形参和实参都是字符指针(在函数内部不能对字符串中的字符做修改
void fun(char *str, int len)
{// 在函数内部不能对字符串的字符做修改,否则报错 段错误//*(str+1) = 'E';//str[2] = 'L';printf("%s\n",str); 
}
void main()
{char *str= "hello";int len = sizeof(str) / sizeof(str[0]);fun(str, len);return 0;
}
  • 实参是指针类型,形参是字符数组
void fun(char str[], int len)
{// 在函数内部不能对字符串的字符做修改,否则报错 段错误// *(str+1) = 'E';// str[2] = 'L';printf("%s\n",str); 
}
void main()
{char *str = "hello";int len = sizeof(str) / sizeof(str[0]);fun(str, len);return 0;
}
注意

1.字符数组在创建的时候,会在内存中开辟内存空间,内存空间可以存放字符数据;字符指针在创建的时候,需要依赖于字符数组,字符指针在内存开辟的内存空间中,存放的是数组元素的地址。字符指针的创建依赖于字符数组,字符数组可以独立存在,而字符指针不能独立存在。

2.字符数组可以初始化,但是不能赋值;字符指针可以初始化,也可以赋值。

案例

案例1

  • 需求:字符指针作为函数参数:用函数调用实现字符串的复制以及长度计算

  • 代码:

/**
* 定义一个函数,实现字符串拷贝
* @param source: 拷贝的源字符串
* @param target: 需要拷贝保存字符串的目标字符串
* @param 字符串长度
*/
int str_cpy(const char *source, char **target)
{//定义一个循环变量register int i = 0;//循环遍历 sourcewhile(source[i] != '\0'){//实现拷贝*(target + i) = *(source + i); //指针法// target[i] = source[i];  //下标法t++}// 拷贝结束后,一定要给target添加\0*(target + i) = '\0';return i;
}int main()
{char source[20], target[20];printf("请输入一个字符串:\n");scanf("%s", source);//拷贝并获取长度int len = str_cpy(source, target);pritnf("字符串:%s 字符串的长度:%d", target, len);return 0;
}

案例2

  • 需求:字符指针作为函数的参数-给定一个字符串,截取start到end之间的字符串,含头不含尾
  • 代码:
/**
* 定义一个函数,实现字符串的截取、
* @param source 源字符串
* @param start  开始位置
* @param end    结束位置
* @param target 目标字符串
* @return 目标字符串长度
*/
int str_substr(char *source, int start, int end, char *target)
{// 定义循环变量(i是source的下标,k是target的下标)	register int i = 0, k = 0;// 遍历源字符串while (source[i] != '\0'){//根据start和end截取if(i >= start && i < end){*(target + k) = *(source + i);k++;}i++;}*(target + k) = '\0';return k;
}int main()
{char *str = "abcdefg";char target[26];int len = str_substr(str,2,5,target);printf("%d,%s,%d\n",str,target,len);return 0;
}

相关文章:

  • Qt C++实现马的遍历问题
  • python 打卡DAY27
  • Vue3项目无法在IE浏览器运行
  • 内存泄漏修复示例
  • 101个α因子#27
  • 第4周_作业题_逐步构建你的深度神经网络
  • C++静态成员变量与对象生命周期解析
  • 前端学习笔记——Promis.All
  • HarmonyOS:帧率和丢帧分析实践
  • 齿轮,链轮,同步轮,丝杆传动sw画法
  • 十进制转二进制
  • Intel oneAPI对OpenCL 的支持
  • kafka在线增加分区副本数
  • OpenCV CUDA 模块图像过滤------创建一个高斯滤波器函数createGaussianFilter()
  • 【计算机网络 第8版】谢希仁编著 第五章运输层 题型总结1 UDP和TCP报文格式
  • 基于labview的声音采集与存储分析系统
  • python绘制股票K线
  • sockaddr结构体详解
  • 学习日记-day13-5.22
  • Python中accumulate方法
  • 销售网站是什么/友链对网站seo有帮助吗
  • 淄博乐达网站建设吧/网络营销具有哪些优势和吸引力
  • 外贸网站怎么做seo/厦门排名推广
  • 域名备案好了后怎么做网站/关键词优化排名费用
  • 免费网站建站 网页/国外市场网站推广公司
  • 怎么申请公司网址/宁波seo排名外包