注释并不能真正将代码从源文件中删除(/**/)
从逻辑上删除C代码——#if指令
#if 0 statements #endif
在#if和#endif之间的程序段可以去除
#include
#include
#include
#define ABC 20``
由预处理器解释的:预处理器读入源代码,根据预处理指令对其进行修改,然后将修改过的代码递交给编译器。
eg:
每个C程序都必须有一个main函数–>程序执行的起点
main函数内容:花括号之间({})
关键字:int 表示函数返回一个整型值
传递方式
数组参数: 引用1
标量和常量: 值
C函数的参数传递规则如下:所有传递给函数的参数都是按值传递的
字符串:一串以2NUL字节结尾的字符。
字符串常量:“ ”中间的
格式化输入与输出 | 非格式化输入与输出 |
---|---|
printf | putchar |
scanf | getchar |
1.在scanf函数的3前未加 & .
2.==与=
环境 | 功能 |
---|---|
翻译 | 源代码被转换为可执行的机器指令 |
执行 | 实际执行码 |
多个源文件经过 编译 ——>目标代码
各个目标文件由 链接器(同时引入库)捆绑在一起——>单一而完整的可执行程序
C源代码——>.C
由#include指令包含到C源代码的文件被称为头文件——>.h预处理命令
cc:C编译器
(1)使用运行时 堆栈 (stack)——>存储函数的局部变量和返回地址
(2)使用 静态 (static)内存——>存储与静态内存中的变量在程序的整个执行阶段一直保留它们的值(即不变)
1.normol:main/exit;
2.break;
3.error.
4.environment
词法规则类似于语法——>你如何在源程序中形成单独的字符段,即 标记 (token)
一个ANSI C程序分为声明和函数。
函数:定义了需要执行的工作。
声明:描述了函数和(或)函数将要操作的数据类型(sometimes=数据本身)
三字母词
eg: ??(——>[ ??<——>{
转义字符 \ \
/**/
唯一非法:相邻的标记之间必须出现一至多个空白字符(或注释)
肥皂盒哲学
关键字[https://blog.csdn.net/CSDN2133/article/details/122010384?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167698178516800180625650%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=167698178516800180625650&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2]共32个:
auto double int struct break else long switch
case enum register typedef char extern return union
const float short unsigned continue for signed void
default goto sizeof volatile do if while static
1.数据类型关键字
A基本数据类型(5个)
void:声明函数无返回值或无参数,声明无类型指针,显式丢弃运算结果
char:字符型类型数据,属于整型数据的一种
int:整型数据,通常为编译器指定的机器字长
float:单精度浮点型数据,属于浮点数据的一种
double:双精度浮点型数据,属于浮点数据的一种
B类型修饰关键字(4个)
short:修饰int,短整型数据,可省略被修饰的int
long:修饰int,长整形数据,可省略被修饰的int
signed:修饰整型数据,有符号数据类型
unsigned:修饰整型数据,无符号数据类型
C复杂类型关键字(5个)
struct:结构体声明
union:共用体声明
enum:枚举声明
typedef:声明类型别名
sizeof:得到特定类型或特定类型变量的大小
D存储级别关键字(6个)
auto:指定为自动变量,由编译器自动分配及释放。通常在栈上分配
static:指定为静态变量,分配在静态变量区,修饰函数时,指定函数作用域为文件内部
extern:指定对应变量为外部变量,即在另外的目标文件中定义,可以认为是约定由另外文件声明
const:与volatile合称“cv特性”,指定变量不可被当前线程/进程改变(但有可能被系统或其他线程/进程改变)
2.流程控制关键字
A跳转结构(4个)
return:用在函数体中,返回特定值(或者是void值,即不返回值)
continue:结束当前循环,开始下一轮循环
break:跳出当前循环或switch结构
goto:无条件跳转语句
B分支结构(5个)
if:条件语句 else:条件语句否定分支(与if连用)
switch:开关语句(多重分支语句)
case:开关语句中的分支标记
default:开关语句中的“其他”分治,可选
C循环结构(3个)
for:for循环结构,for(1;2;3)4;的执行顺序为1->2->4->3->2…循环,其中2为循环条件
do:do循环结构,do 1 while(2);的执行顺序是1->2->1…循环,2为循环条件
while:while循环结构,while(1) 2;的执行顺序是1->2->1…循环,1为循环条件
以上循环语句,当循环条件表达式为真则继续循环,为假则跳出循环。
1、基本数据类型: signed unsigned char int float double short long void
2、构造数据类型: struct union enum
3、数据存储类别: auto static extern register
4、数据优化: const volatile
5、9条基本语句: if else switch case break default while do for return continue goto
6、其它: typedef sizeof
预编译处理符 “#”
#include
#define
#ifdef
#ifndef
#if
#else
#else if
#endif
等等。
1、unsigned :无符号的
//用来声明一个无符号的变量。
unsigned char var; //var的范围:0~255
2、signed :有符号的(可以省略不写)
//用来声明一个有符号的变量。
signed char var; //var的范围:-128~127
3、char :字符型
//用来声明一个字符型变量。
//占一个字节空间
char var;
4、int :整型
//用来声明一个整型变量。
//C51:占两个字节空间,ARM:占四个字节
int var;
5、float :浮点型
//用来声明一个浮点型(实型)变量。
//最多能表示到7个有效数据位。
//占四个字节空间
float var;
6、double :双精度型
//用来声明一个双精度实型变量。
//最多能表示到15~16个有效数据位。
//占四个字节空间 ,有的系统占八个字节
double var;
7、short :短整型
//用来声明一个短整型变量。
//C51:跟int一样,ARM:占两个字节
short var;
8、long :长整型
//用来声明一个长整型变量。
//ARM:跟int一样,C51:占四个字节
long var;
9、void :空型
//表示一个函数没有返回值,或者无形参。
void function(void);
1、struct
//用来声明一种结构体类型。
struct stu{
char sex;
int age;
float score;
struct stu *Next;
};
struct stu var;
2、union
//用来声明一种共用体类型。
//该类型的变量所在空间的大小以其成员占最大的那个为准,
//存入该变量中的值以程序中最后存入的数值为当前值
union non{
char sex;
int age;
float score;
};
union non var;
3、enum
//用来声明一种枚举类型。
//规定枚举类型的变量,只能在限定的范围内取值
//否则,编译会出现警告(达到数据安全的效果)
enum em
{a = 23,b,c,d = 56,e}; //其中b=24,c=25,e=57
enum em var;
1、auto :自动的(可省略不写)
//定义一个局部变量,默认为auto类型的,
//当它所在的函数调用结束时,释放内存
//使用时才分配内存,用完即释放
auto char var;
2、static :静态的
//①定义一个局部变量,该变量在定义时只进行
//一次初始化,以后每次调用它所在的函数,其值
//都会保持上一次调用的结果,它所在的空间不会
//被释放
//②被static修饰的全局变量,则只能在它所在的C
//源文件中使用,其它文件不能调用,(内部全局变量)
//③被static修饰的函数,只能在该函数所在的C源文
//件中被调用,其它文件不能调用,(内部函数)
static char var;
static void function();
3、extern :外部的
//①想要调用别的C源文件中的某一个全局变量,
//可以使用该关键字在该文件中修饰声明该变量
//即可调用(前提是该变量没有被static修饰)
//该类型的变量也是一直占着内存不释放
//②想要调用别的C源文件中的某一个函数,
//可以使用该关键字在该文件中修饰声明该函数
//即可调用(前提是该函数没有被static修饰)
extern char var;
extern void function();
4、register :寄存器的
//被这个关键字修饰的变量,建议编译器将该变量在
//使用时放到CPU内部寄存器中,以提高执行效率
//注意:该关键字只是"建议",到底有没有将变量放到
//寄存器中无从得知。一般使用在循环次数比较多的
//地方。
//在使用时才分配内存,用完即释放
register long i = 30000;
1、const :常的
//常变量:被const关键字声明的变量,其值不能被改变。
//即在声明该变量时必须要初始化该变量。
//var本身还是一个变量。(数据安全检测)
const char var = 100;
char arr[var]; //试图声明一个长度为100的字符型数组
//在MDK (ARM)中可以使用常变量来声明数组的长度
//在VC++编译环境中也可以。
//在C51-keil中不可以使用常变量来声明数组的长度
char const p;
//指针变量p不可改变,但是它指向的地址里面的值可变
char constp; 或 const char p;
//指针变量p可以改变,但是它所指向的地址里面的值不能改变
const char const p; //p地址不可改变,里面的值也不能变
2、volatile :随时会改变的
//被volatile修饰的变量或寄存器会意想不到地发生改变。
//①某些变量或寄存器(如状态寄存器)可能会受硬件影响;
//②在多线程任务中,被其它线程修改(共享内存段);
//③一个在中断服务中使用到的全局变量
//④编译器会对C程序进行优化;
//为了保证程序不被优化,保证CPU取到的数据是最新的
//(即提醒CPU每次都必须到内存中取出变量当前的值而不
//是取cache或者寄存器中的备份),使用该关键字修饰,如:
int *p;*p = 1; p = 2;
//编译时,编译器会对上面的语句进行优化,
//会直接优化成:
intp; p = 2;
//为了保证上面的语句不被优化,加volatile修饰变量:
int volatile p;
四种结构:
1、顺序结构:0条 //声明语句、运算语句、赋值语句等等
2、选择结构:2条 //多选一
①、if -else if -else if ... else
if(表达式1)
{语句s;}
else if(表达式2)
{语句s;}
else if(表达式3)
{语句s;}
else
{语句s;}
//用法:顺序判断if后的"表达式"是否为真
//如果碰到为真的情况,则执行其下面的{}里的"语句"
//执行完后,即退出这个"多选一"的结构
②、switch-case-break
switch(变量)
{
case 常量1:语句;…;break;
case 常量2:语句;…;break;
case 常量3:语句;…;break;
default:语句;
}
//用法:顺序判断"变量"是否与"常量"相等,
//如果相等,则执行该常量:后的"语句s",遇到break即跳出
//这个结构
unsigned char i = 6;
unsigned char dat;
switch(i)
{
case 3:dat = 5;break;
case 5:dat = 34;break;
case 6:dat = 99;break;
case 7:dat = 56;break;
case 6:dat = 100;break;
default:dat = 68; //默认执行
}
//注:如果少了break,则顺序判断i的值与
//case后面的常量是否相等,如果相等,则执行其
//后面的语句,以后不再判断,再继续执行下面的
//每一条case 后面的语句,直到default.
//这种用法不使用!
3、循环结构:3条
①、for
for(语句1;语句2;语句3)
{
语句4;
语句…;
}
//用法:语句1:条件初始化
// 语句2:判断语句,判断条件是否成立
// 语句3:修改条件语句
//先执行语句1,再进行对语句2的判断,如果成立
//则执行{}里的语句4…,再执行语句3,在判断
//语句2是否依然成立,。当语句2不成立时,结束循环
②、while
while(表达式)
{
语句;
…;
}
//用法:先判断“表达式”是否成立,如果成立
//则执行{}里的语句,执行完再次判断“表达式”
//是否依然成立,成立则继续执行{},不成立则结束
//此循环结构。
如何来设计一个死循环?两种方法:
for(;)
while(1)
③、do-while
do{
语句1;
…;
}while(表达式);
//用法:先执行{}里的语句,执行完后,判断
//"表达式"是否成立,如果成立,继续执行{};
//如果不成立,则结束循环
4、转移结构:4条
①、break
//仅用于跳出循环结构
//且仅能跳出一层循环结构
for(i=10;i>0;i–)
{
t = 10;
while(t–)
{
dat++;
if(dat == 3)
break;//跳出while()结构。
}
}
②、continue
//用于终止本次循环,继续从下次循环开始
//正式程序中不使用,仅用于调试程序
char buf = 10;
while(buf–)
{
a++;
b++;
continue;//遇到continue则结束这次循环
d++; //这条永远都不会执行到
e++; //这条永远都不会执行到
}
③、goto
//无条件转移
//一般都不建议在大的程序当中使用
unsigned char dat=10;
while(dat–)
{
a++;
b++;
Lable: c++;
if(c == 3)
goto Lable;//直接跳到Lable标号去
d++;
}
④、return
//用于函数返回,
//在函数调用时,遇到return即返回。
//如果需要返回某个值,在其后加上返回值。
//返回值类型必须和函数类型一致。
void function()
{
char a,b;
a++;
return; //遇到return即返回调用处
b++; //不会被执行
return; //不会被执行
}
1、typedef : 类型重定义
typedef unsigned char uchar;
//用uchar重新定义unsigned char
#define uchar unsigned char
//用uchar 替换unsigned char
跟宏定义 的区别:
①、typedef 是在编译阶段进行定义
宏定义是在预编译处理阶段完成展开
②、typedef 是类型重新定义,不是简单地替换
宏定义只是简单的替换,没有定义
typedef unsigned charM;
#define M unsigned char
M p1,p2;
//对于typedef来说:p1是指针变量,p2也是
//对于宏定义来说:p1是指针变量,p2是普通变量
2、sizeof
//用来求类型所占的字节数
int var = 10;
char g;
g = sizeof(var++);//g = 4;
//注意:var++该条语句没有被执行!
//()里的语句是不会被执行的。
较合理的组织形式:
一个C程序的源代码保存在一个或多个源文件中,但一个函数只能完整出现在同一个源文件中。
C程序的源文件应该包含一组相关的函数&&(使实现抽象数据类型成为可能)。
每个源文件分别编译,最后合体
使用Tab键
别人看的懂
类型,特点,声明
变量的三个属性——作用域、链接属性、存储类型即
可视性(它在什么地方可以使用) + 生命期(值能保存多久)
4种基本数据类型——整形、浮点型、指针、聚合类型
字符 短整型 整形 长整型 (搞这么复杂,不就是字符和整形吗)
有符号 无符号
字符在本质上是小整型值
字面值:字面值常量——一种实体,指定了自身的值&&不允许发生改变
它的值是符号常量非字面值的类型
enum
每个内存位置都由地址唯一确认并使用.
指针只是地址的另一个名字.
指针变量就是一个其值为另外一个(一些)内存地址的变量
使用字符串常量会生成一个“指向字符的常量指针”,当一个字符串常量出现于一个表达式时,表达式所使用的值就是这些字符所存的地址。因此,可以把字符串常量赋值给一个“指向字符的指针”,后者指向这些字符所存储的地址.
不能把字符串常量赋值给一个字符数组,因为字符串常量的直接值是一个指针,而不是字符本身.
所以调用库函数操纵.
结构方面
应该使用tupedef而不是#define来创建新的类型名,因为后者
#define d_ptr_to_char char *
d_ptr_to_char a, b
正确的声明了a但b却被声明为一个字符,在关于指针是,用typedef更为合适
const
局部变量局部访问
四种类型:
避免在嵌套的代码块中出现相同的变量名
全局
参数名冲突
只适用于语句标签,语句标签用于goto语句,即一个函数中的所有语句标签必须唯一
external(外部):表示同一个实体
internal(内部)
none(无):单独的个体
指存储变量值的内存类型–决定变量何时创建、何时销毁、它的值将保存多久。
存储变量的3个地方:普通内存、运行时堆栈、硬件寄存器。(不同地方有不同的特性)
auto static register extern
静止变量:0
自动变量:垃圾值
见3.7
只包含一个分号
= ==
{}
当else悬空,找最近的
循环的测试在循环体开始之前进行
break:永久终止循环,跳出循环
continue:结束当前循环,进行测试,判断是否进入下一次循环
便于把所有用于操纵循环的表达式收集在一起,便于寻找。
至少执行一次
最后一个case其实不用,只是以后是维护方便
所有的值都不跟case匹配
可以用于检测任何非法值
尽量不用
operator
按照优先级分组
+ - * / %
<< >>必须为整形
不可用a << -5
右移位:逻辑移位和算数移位(当操作值为-(即最高位为1)时,不同)
逻辑移位:用0补充(与左移位相同)
算术移位:移入的位由先前该值的符号位决定,1 1|| 0 0
AND
OR
XOR
+=效率更高
!求反
&产生操作数的地址
~求补1-0 0-1
C用整数代替布尔类型
if(a)=if(a!=0)
if (a==0)=if(!a)
&&:比> <都要低 ,如果左边的值非零则不再求值
||:如果左边的值为1,则直接输出
被称为短路求值–测0和非0
表达式1?表达式2:表达式3
优先级很低,一般不加括号也没有问题
a,b,c逗号操作用于将两个或多个表达式分割开来,自左向右逐个求值,即输出的值为最后一个值(c)
也有优点
while(a>0)
{
a=get();
asd(a);
}
变为
while(a=get(),asd(a),a>0) 易于维护
下标:[] ——并不仅限于数组名
下标引用接受两个操作数:数组名和索引值
下标值总是从零开始,不会对下标值进行有效检查。
array[]——*(array+1)等价(优先级不同)
函数调用接受一个或者多个操作数。第一个是希望调用的函数名,剩余的操作数就是传递给函数的参数。
将函数调用以操作符的方式实现——表达式可以代替常量(第七章)
. ->都用于访问一个结构的成员。
若s是个结构变量,s.a访问s中叫a的成员
若s是个指向结构的指针,用->访问其内容
C 不具备显式的布尔类型,用整数代替
0是假,其余为真
a=b+25;
a可为左右值,b只可为右值
类型转换
lexp:左值表达式——位置
rexp:右值表达式——值
使用临时变量,让函数调用再单独的语句中进行
基础
位——字节——int
10亿=4G
硬件事项:边界对齐——int存储的起始位置只是特定的字节(通常是2/4的倍数)
·内存中每个位置都有唯一的地址标识
·内存中的每个位置都包含一个值
高级语言通过名字来访问内存位置——a,b(即变量)——编译器来实现
硬件仍然通过地址访问内存位置
*:间接访问/解引用指针
声明一个指针变量并不会自动分配内存
初始化
不指向任何东西,对NULL * 是非法的(ERROR),不可传递
*&a=25;
&产生a的地址,*访问地址——等价于a=25;
**c:二级指针
char ch=‘a’;
char cp=&ch;
1.&ch cp &cpcp
2.cp+1(cp+1)
3.++cp cp++ ++cpcp++ (cp)++
4.++++cp ++*cp++
当一个指针和一个整数量执行算数运算时,整数在执行加法运算前会调整——指针所指向类型的大小.
指针±整数
指针-指针(两个指针都指向同一个数组中的元素中)=减值/元素长度
避免使用
函数:函数体的实现
函数体:一个代码块,被调用时执行
被调用时,返回——实现一种有用的存根目的(为尚未实现的代码保留一个位置)——保持完整性
void:无返回值
return 0 || return (0)
没有见到原型,认定为整型
传值调用:函数获得参数值的一份拷贝,不会改变实参.
传址调用:被传递的参数是一个数组名并使用下标引用该数组的参数——数组名实际上是一个指针,下标引用是间接访问的另一种方式.
C可用于设计和实现抽象数据类型(ADT,Abstract Data Type),可以限制函数和数据定义的作用域(static).——黑盒设计.
黑盒实现细节与外界隔绝,访问的唯一方法是通过模块所定义的接口.
模块具有功能说明(模块所执行的任务)和接口说明(模块的使用).
C通过运行时堆栈支持递归函数(直接或间接调用自身的函数)的实现.
效率低,简单,不去追究细节的实现过程
理解函数所声明的变量是如何存储的!
当函数被调用时,它的变量的空间是创建于运行时堆栈上的,以前调用的函数的变量仍保留在堆栈上,但被新函数的变量所覆盖,无法访问.
就是一个循环覆盖的过程,区分分属不同的区.
当重复调用结束时(类似循环)(不同的是,会保存堆栈中的变量值),开始打印输出,return,并开始销毁堆栈上的变量值.
递归的两个特性:存在限制条件,使递归stop
逐渐趋近
递归的开销:参数必须压到堆栈中、为局部变量分配内存空间、寄存器的值必须保存.
迭代实现:可读性稍差,但效率更高.
即使用循环和交换值
函数原型只能显示固定数目的参数,考虑实现让一个函数在不同的时候接受不同数目的参数,当然,有一些限制.
即需要一种机制,能够以一种良好的方法访问数量未定的参数列表.
这就是解决办法,宏定义于stdarg.h头文件,是标准库中的一部分.
这个库声明了一个类型va_list和三个宏——va_start、va_arg、va_end,相互配合,访问参数的值
#include
float average( int n_values,....)
{
va_list var_arg;
int count;
float sum = 0 ;
va_start(var_arg,n_values );//访问可变参数
for(count = 0; count < n; count +=1 )//添加取自可变参数列表的值.
{
sum += va_arg( var_arg, int);
}
va_end( var_arg);
return sum / n_values;
}
很危险,因为都是缺省认定
多维数组、指针、初始化
int b[4];
b是什么?—— b表示整个数组,错.b是一个指针常量,是数组第一个元素的地址,类型取决于数组元素的类型.
(常量的值不能修改)why?——在程序完成链接后,数组的位置固定,当程序运行时,便无法移动
数组具有确定数量的元素,而指针只是一个标量值,当数组名使用时,编译器才会为它产生一个指针常量.
有两种情况,数组名不用指针常量来表示:
1.数组名作为sizeof操作符或单目操作符&.
sizeof返回整个数组的长度(不是指针的长度),&数组名产生一个指向数组的指针(不是指向某个指针常量值的指针)
int array[10];
int *ap = array + 2;
ap array+2 = &array[2]
*ap array[2] = *(array+2)
ap[0] *(ap+(0))=array[2]
不要惯性思维,C的下标引用等价于间接访问
ap+6 array+8=&array[8]
*ap+6 array[2]+6
*(ap+6) array[8]
ap[6] *(ap+6)=array[8]
&ap 合法但目前不知道ap在哪里
ap[-1] array[2-1]=array[1]
ap[9] 非法,但很多编译器不报错,而且不检查相应下标错误,可能会随机给出数字
下标绝对不会比指针更有效率,但有时候指针会比下标更有效率
正确的使用指针
C里面所有的参数传递都是传值的方式,指针能通过间接访问更改实参的值,是因为数组的传值调用传递的是参数的一份副本,可以自由操纵
eg: *string++
取得string所指向的那个字符,并修改string,使其指向下一个字符
int a;
int b[10];
int c[6][10];
int d[6][6][10];
a是一个简单的整数,增加了一个维数,b是一个向量,包含10个整型元素.
c只是在b的基础上再增加一维,c可以看成一个包含6个元素的向量,只不过它的每个元素本身是一个包含10个整型元素的数组。
d就是一个3排、6行、10列的整型三维数组.
在C中,多维数组的元素存储顺序按照最右下标率先变化的原则,称为行主序.
遵守数组元素的实际存储方式.
int matrix[3][10]
matrix[1][5]
matrix 类型:指向包含10个整型元素的数组的指针
值:指向包含10个整形元素的第一个子数组
matrix + 1 指向matrix的另一行
注意1是根据数组的长度进行调整
*(matrix + 1) 下一行的数组的第一个元素
=matrix[1]
*(matrix + 1) + 5 下一行的数组的第六个元素
*(*(matrix + 1) + 5) 即*(matrix[1]+5)
即matrix[1][5]
太妙了!!!
int a[10],*b=a;
int c[3][10],*d=c;//非法,初始化错误
int (*p)[10];//下标引用的优先级高于间接访问,[]使得间接访问首先执行
int (*p)[10] = a;//使p指向a的第一行
int *pi=&a[0][0];
int *pi=a[0];//指向a的第一个整型元素
字符串以字符串常量的形式出现或者存储于字符数组中——C语言没有显式的字符串数据类型.
'\0’结尾
NUL
size_t strlen(char const *string)
size_t是在头文件stddef.h中定义的,是一个无符号整数类型
寻找一种更好的算法比改良一种差劲的算法更有效率
复现已经存在的软件比重用已经存在的软件比重新开发一个效率更高
程序员要自己判断
char *strcpy(char *dst,char const *src)
char *strcat(char *dst)
返回一个指向目标函数的指针——可以嵌套使用
strcat(strcpy(dst,a), b)
很多时候他们的返回值都会被忽略
int strcmp(char const *s1,char const *s2)
s1
s1=s2 =0
还有一些函数以另一种不同的方式处理字符串,这些函数接收一个显式的长度参数,这种机制可以防止难以预料的长字符串从他们的目标数组溢出
char *strncpy( char *dst, char const *src, size_ t len );
char *strncat( char *dst, char const *src, size_ t len );
int strncmp( char const *s1, char const *s2, size_ _t len);
strncpy:如果strlen(src)
找到后返回一个指向该位置的指针,if not just return NULL
char *strchr(char const *str,int ch)
char *strrchr(char const *str,int ch)//她所返回的是一个指向字符串中该字符最后出现的位置(当有多个值时,即最右边那个)
查找任何一组字符第一次在字符串中出现的位置
char *strpbrk( char const *str, char const *group)
返回一个指向str中第一个匹配group中任何一个字符的字符位置,if not just return NULL
char *strstr( char const *s1, char const *s2)
返回一个指向s1中第一个匹配s2中第一个一个字符的字符位置,if not just return NULL
简化从一个字符串中查找和抽取一个子串的过程
strspn、strcspn用于在字符串的起始位置对字符计数
size_t strspn( char const *str, char const *group)
就是从str的第一个元素开始往后数,看str中是不是连续往后每个字符都在group中可以找到。到第一个不在gruop的元素为止。看从str第一个开始,前面的字符有几个在group中
#include
#include ;
int main() {
int len1, len2;
char buffer[] = "25,142,330,Smith,J,239-4123";
len1 = strspn(buffer, "0123456789");
len2 = strspn(buffer, ",0123456789");
printf(" len1为:%d; len2为:%d", len1, len2);
getchar();
return 0;
} 结果len1=2;len2=11;
size_t strcspn( char const *str, char const *group)
用来检索字符串s1开头连续有几个字符都不含字符串s2中的字符
strcspn中的C来源于求补这个概念
从字符串中隔离各个单独的称为标记(token)的部分,并丢弃分隔符
char *strtok( char *str,char const *sep)
为什么str前面无const——strtok函数会修改它所处理的字符串
if str const 则复制一份在传递给strtok函数
[^在其他语言中,这种叫做过程]
即地址调用. ↩︎
字符串终止符(不是字符串的一部分)
·是ASCII字符集中‘\0’字符的名字,字节模式为全0.
·NULL在头文件stdio.h中定义,不存在预定义的符号NUL,若要使用他而不是字符常量‘\0’,就必须自行定义
↩︎
在C语言中,枚举型、字符型和各种整数的表示形式统一叫做标量类型.当在C表达式中使用标量类型的值时,编译器就会自动将这些标识符转换为整数保存.这种机制的作用是,在这些标量类型上执行的操作与整型上执行的操作完全一样. ↩︎