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

C语言中级_宏定义传参、volatile和extern关键字、字符串数组和字符串函数

0、前言:

  • 宏定义传参可以理解成一种更便捷的函数,但和函数有明显区别的一点就是宏定义传参主打一个替换,其次就是实现简单逻辑可以,复杂的就不行了。
  • volatile关键字和extern关键字是干什么的要知道即可
  • 字符串数组很重要,特别是定义方式很重要,还有就是常用的字符串函数要知道其作用,传入的参数,是否有返回值。特别是传入的参数和返回值类型,很重要,不像python记个差不多就行,在c中函数使用非常严谨。

1、宏定义传参:

  • 1.1、单条语句举例:#define len(arr) sizeof(arr)/sizeof(arr[0]) // 宏定义传参单条语句
  • 1.2、多条语句举例:#define swap(a,b,type) { type temp;temp = a;a = b;b = temp;} // 宏定义传参多条语句(★)

2、两个了解即可的关键字:

  • volatile关键字避免寄存器优化,导致结果不一致,这个和常量修改有关系,比如在C++中通过指针地址强制修改常量的值会触发寄存器优化,导致指向常量的指针值可以改变,但常量的值被优化保存了下来。
  • extern关键字用于声明外部"变量"或"函数",表明该变量或函数的定义在其他文件(或当前文件的其他位置),告诉编译器 “这个标识符在别处已经定义过了,这里只是引用它”。如果是其他文件定义的静态变量(static),那么则不能通过这种方式引用。一般而言,最好是通过头文件管理外部变量声明。

3、字符串数组(C语言中的字符串):

  • 定义:在 C 语言中,字符串实际上是使用空字符 \0 结尾的一维字符数组。因此,\0 是用于标记字符串的结束。
  • 补充:在C语言中NULL 是一个 指针,用于表示指针不指向任何有效地址。不能用NULL代替\0,因为\0是一个字符,为什么用\0作为字符串结束符呢?因为用0结束会误认为是字符0,因此加个转移符号\作为结束符。
  • ★字符数组初始化时长度超过定义长度会报错,长度小于定义长度,后面会全部补\0,用一整个字符串给字符数组初始化时,不写长度,它会自动补\0,如果是逐个字符初始化要记得最后加\0,否则不识别字符串结束位置。
  • \0作为字符串结束符是很重要的一个知识,有时候设置字符串数组大小的时候,忽略这个问题就会出错,下面用代码来演示一些只可意会的东西:
#include<stdio.h>
#include<stdlib.h>
int main() {// 指向字符串数组指针的指针// 逐个字符初始化char a1[] = { 'a','b','c' };char a11[] = { 'a','b','c' ,'\0'};printf("a11:%s", a11); // a11:abc// 定义100个字符的字符串数组char a[100] = ""; //这样定义就是空间为100的字符串数组,合法;// 逐个字符显式指定长度初始化char a2[4] = { 'a','b','c','\0' }; char a3[5] = { 'a','b','c'}; // 会自动补\0,初始化时提供的字符数量小于数组长度,编译器会自动用 '\0'(空字符)填充剩余部分,直到填满整个数组。// 直接初始化char a4[] = "abc"; // 自动计算大小这个过程会给最后加\0;char a5[3] = "abc";// 使用字符串指针初始化【规则:指针必须指向一个地址】//char * a6 = { 'a','b','c' }; // char * 是一个指针,指向 char 类型的数据地址,{ 'a','b','c' }是一个数组,因此不合法;char * a6 = "abc";  // "abc"是字符串字面量,程序编译时会自动将其首地址返回给指针,因此合法;char* a7 = (char*)malloc(4 * sizeof(char));int i;if (a7 != NULL) {// 拷贝字符串到动态内存for (i = 0; i < 3; i++) {a7[i] = a6[i];}a7[i] = '\0';printf("a7:%s\n", a7);  // 输出 a7:abcfree(a7);           // 必须释放!}//a7 = "hello"; // 错误,相当于你又改变了a7的指向,并没有给动态空间存放内容。// 部分初始化char a8[5] = "abc"; // 自动补\0;// 截断初始化//char a9[5] = "abcdef"; // 编译警告不合法;// 常量指针初始化char const* a9 = "abc";// 容易混淆的概念:存放字符串指针的数组char* a10[3] = { a1,a2,a3 };printf("a1:%s\n", a1); //a1:abc烫烫烫烫烫烫烫烫烫烫烫烫烫烫蘟bcprintf("a2:%s\n", a2); //a2:abcprintf("a3:%s\n", a3); //a3:abcprintf("a4:%s\n", a4); //a4:abcprintf("a5:%s\n", a5); //a5:abc烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫虅? ?printf("a6:%s\n", a6); //a6:abcprintf("a8:%s\n", a8); //a8:abcprintf("a9:%s\n", a9); //a9:abcfor (i = 0; i < 3; i++) {printf("i:%d,%s\n",i, a10[i]);}/*i:0,abc烫烫烫烫烫烫烫烫烫烫烫烫烫烫蘟bci:1,abci:2,abc*/return 0;
}	

4、字符串函数:

  • 要在C语言中使用字符串数组,就要在预处理命令中引入string.h头文件;在visual studio中还有还有一个很有帮助的功能,就是写出来这种头文件中引用的函数之后,如果忘记函数参数,可以鼠标悬停在该函数上面查看函数的形参。
  • 内存操作函数:以mem开头的函数
// 下面演示核心代码,省去了C语言代码结构
char a[5] = "abcd";
char b[3] = "ef";
memset(a, 'm', 2); // 将内存块a的前2个字节都设置为字符m(按 ASCII 值)
printf("a:%s", a); // a:mmcd
printf("\n-----------\n");memcpy(a, b, 1); // 从b复制1个字节到a
printf("a:%s", a); // a:emcd
printf("\n-----------\n");
  • 字符操作函数:以str开头
// 下面演示核心代码,省去了C语言代码结构
printf("strlen(ad b ):%zu", strlen("ad b ")); //strlen(ad b ):5  计算字符串的长度(不包含终止符\0)。
printf("\n-----------\n");strcpy(a, b);
printf("a:%s", a); // a:ef
printf("\n-----------\n");strncpy(a,"abc",3);
printf("a:%s", a); // a:abcd
printf("\n-----------\n");char c[10] = "ab";
strcat(c, a); //将a字符串拼接到c末尾(c原\0被覆盖,拼接后加\0)。
printf("c:%s", c); // c:ababcd
printf("\n-----------\n");strncat(c, "mm",1); //将"mm"字符串中前n个拼接到c末尾(c原\0被覆盖,拼接后加\0)。
printf("c:%s", c); // c:ababcdm
printf("\n-----------\n");printf("%d", strcmp("aBc", "AbC")); // 1 按 ASCII 值逐字符比较
printf("\n-----------\n");printf("c字符串的开始位置:%p,找到'b'的位置:%p", c, strchr(c, 'b')); // c字符串的开始位置:000000DB1C58FAC8,找到'b'的位置:000000DB1C58FAC9
printf("\n-----------\n");printf("c字符串的开始位置:%p,找到最后一个'b'的位置:%p", c, strrchr(c, 'b')); // c字符串的开始位置:00000081CB0FF8F8,找到最后一个'b'的位置:00000081CB0FF8FB
printf("\n-----------\n");// strpbrk理解起来会难一些
printf("c字符串的开始位置:%p,找到最后一个“efgca”中任一字符第一次出现的位置:%s", c, strpbrk(c, "efgcb")); // c字符串的开始位置:000000CFDA2FFBF8,找到最后一个“efgca”中任一字符第一次出现的位置:babcdm
printf("\n-----------\n");printf("c字符串%s中bcd在第%zu位", c,(strstr(c, "bcd") - c)); //c字符串ababcdm中bcd在第3位
printf("\n-----------\n");// strtok():分割原字符串
char d[30] = "a,b,c d e";
printf("d:%s\n", d);
char* p1 = strtok(d, ", ");
while (p1) {printf("p1:%s\n",p1);p1 = strtok(NULL, ", "); // 这是用strtok连续分割时的固定写法
}
/*
d:a,b,c d e
p1:a
p1:b
p1:c
p1:d
p1:e
*/
printf("\n-----------\n");
  • 字符判断函数:以is开头
// 下面演示核心代码,省去了C语言代码结构
char e[5] = "A2,aB";
printf("%d\n", isalpha(e[0])); // 1
printf("%d\n", isdigit(e[1])); // 4
printf("%d\n", isalnum(e[2])); // 0
printf("%d\n", isupper(e[3])); // 0
printf("%d\n", islower(e[3])); // 2

总结:

  • 宏定义传参可以理解为一种基于替换方法简单逻辑的函数。
  • 字符串数组的重点内容就是怎么样初始化一个字符串数组。
  • 字符串函数的重点就是详细掌握这些函数当中的参数。
http://www.xdnf.cn/news/17394.html

相关文章:

  • Python Gradio 写的-文本情感分析小软件 (不用Html+css+js 可写出网页来)
  • Mac屏幕取色不准?探究原理和换算规则
  • STM32学习笔记6-TIM-2输出比较功能
  • PyQt5技术栈简述
  • SpringBoot日志关系
  • react之React.cloneElement()
  • 数据结构初阶(7)树 二叉树
  • Spring——Spring懒加载设计使用场景
  • try/catch/throw 简明指南
  • 零拷贝技术:提升传统I/O的性能
  • 理解协议最大传输单元(MTU)和TCP 最大报文段长度(MSS)
  • 【ros_humble】3.人脸检测python(服务通讯和参数通讯介绍)
  • jenkins-飞书通知机制
  • mac安装node.js
  • 前端懒加载技术全面解析
  • Yi大模型-零一万物发布的开源大模型
  • [FOC电机控制]霍尔传感器于角度问题
  • Docker容器部署Tomcat线上商城
  • golang的二维数组
  • AI工具在数据质量管理中的应用
  • windows10 ubuntu 24.04 双系统 安装教程
  • Ubuntu和Windows系统Kafka配置方法
  • Linux的软件防火墙iptables
  • 机器翻译实战:使用Gensim训练中英文词向量模型及可视化
  • QML开发:高级布局组件
  • 【Python 语法糖小火锅 · 第 1 涮】
  • 论文阅读 2025-8-3 [FaceXformer, RadGPT , Uni-CoT]
  • 矩阵的条件数 向量的条件数
  • 大疆上云之SRS视频流服务配置
  • “黑影御剑飞行”视频引发的思考