说明:笔记内容是观看翁恺老师的C语言课程视频中记录的,笔记内容有部分来自于原文内容,有部分来自于自身的思考实验。
以下排列顺序以一个视频为一个片段(内容比较多,可能不适合喜欢快餐方式的朋友):
根据测试,目录有时可能没法跳转准确(可能是因为内容太多的原因,可以考虑用左下方侧的目录跳转)
目录
同样的,也可自己写出一个与strcmp函数作用相同的函数。(如果想更改返回值为-1、0、1的话,只需要在最后加入判断并返回即可)
套路一:寻找第二甚至其他地方的字符位置时,可以将第一个字符返回值加一。
套路二:进行拷贝字符串的部分内容时,可以通过改变其中字符为’\0’,最后恢复回去。
一、字符串
字符数组
不是C语言的字符串,因为不能像字符串方式做运算。
字符串
与字符数组的区别:结尾有’\0’使得它成为在C语言中可以使用字符串的运算方式进行运算。(其中’\0’可替换为0,但是不可用’0’,因为后者是一个字符)
特性:
- 0标志字符串的结束,但不属于字符串的一部分;
- 计算字符串长度的时候不包括0;
- 字符串以数组形式存在,但以数组和指针形式访问(后者居多);
- string.h里有很多处理字符串的函数(用法:加入include<string.h>在代码头上);
- 不能用运算符对字符串做运算(其他一些语言可以,例如用+号连接两个字符串);
- 可通过数组方式遍历字符串;
- 唯一特殊点在可以用字符串字面量初始化字符数组;
定义变量及初始化;
其中里面的内容代表字符串的字面量(或者叫字符串常量),最终结尾会有’/0’存在,但不可见。
其中两个相邻的字符串常量会自动连接起来(两种连接方法)
法一:
此时前后两个里面内容会合并为一个内容,如:
法二:
此时会将第二行的内容接上第一行,但会从起始点位置接收所有内容,如:
二、字符串变量
指针形式定义字符串变量:
如果字符串变量定义时,以指针形式定义,将会变成只读的形式,此时对字符串里面的内容做修改,编译器会出错。
如:
这一段的代码会使编译器出问题,出现报错或者无法正常输出值。
原因:char *a实际上是从const char *a,但是由于历史原因,编译器接受不带const,
但试图写入仍会出错。
当两个指针字符串字面量相同时,它们地址相同,均指向同一片地方。
如:
数组形式定义字符串变量:
如果以数组形式定义,那么字符串将可以改变其中值。
如:
总结:
构造字符串—>数组
①作为本地变量空间自动被回收;
②知道字符串位置。
处理字符串—>指针
①不知道字符串位置;
②处理函数参数时;
③用malloc动态分配空间时。
三、字符串输入输出
①scanf读入字符串时(到空格、tab或回车为止),存在局限。
解法:可利用如gets( )来读入字符串,此时仅当回车时结束读取,并用puts( )输出。
②scanf在读取字符串时,因为没规定上界,可能会导致读取内容超过字符串数组存储空间,存在危险。(虽然一时没事,但之后一定会出问题)
解法:可在%s读取时,在%与s间加入数组长度减一的数字,限制读取个数。
如:
③对字符串变量使用前,要做初始化。
如:
这个字符串为空字符串,。
因此,对于,该数组长度仅为1,且
。
四、字符串数组,以及程序参数
字符串数组几种定义方式:
1.char **a指的是定义时a为一个指针,指向另一个指针,那个指针指向一个字符(串)。
因此它无法做到储存多个字符串。
2.char a[ ][ ]代表a是一个二维数组,而在数组定义里面,必须给出列数。
例:a[ ][10]的储存
如图,第三行的字符串显然超出了数组的储存列数,会使得编译出错或存在危险。
因此它无法做到储存不定上限长度的字符串。
3.char *a[ ]代表a为一个数组,数组里每一个单元都是指针,指向一片空间。
如:
此时可以做到储存未知字节数的字符串(不超过计算机内部最大储存空间情况下)。
因此它可以做到储存多个不定上限长度的字符串。
用途之一:
完善之前月份英语的代码,使其变为单一出口,增加安全性。
程序参数:
main的函数括号里面的内容,便是它的程序参数。
其中argv[0]是命令本身。
在windows运行时:
运行结果:
因此在Windows运行时显示的是其目录名。
在Unix中,当使用Unix的符号链接时,反映符号链接的名字。
例如,可以在输入a.out之后,接入my,此时my相当于是a.out的一个快捷方式,其指向的便是a.out。(感兴趣的可以搜busybox查找)
五、单字符输入输出
putchar
形式:int putchar(int c);
作用:像标准输出写入一个字符。
返回类型:返回写了几个字符,EOF(-1)表示写失败。//根据视频描述
Ps:在自己试验时,发现putchar返回值实际是第一个字符的Ascll码(%d方式输出,且写成功情况下)。
下面为测试代码:
运行结果:
根据查询Ascll码表,发现h对于的值正好为104。
后面根据查询结果,根据试验后发现printf函数的返回值,才是返回的字符数(且一个汉字对应两个字符数)
下面为测试代码:
运行结果:
getchar
形式:int getchar(void);
作用:从标准输入读一个字符。
返回类型:int,作用是为了返回EOF(-1)。
部分指令:
一、
Windows—>Ctrl + Z
Unix—>Ctrl + D
上面二者方式均为输入EOF(-1)
二、
Ctrl + C指令表示强制关闭程序。
运行原理:
其中shell相当于一个中间商,将电脑输入的东西进行处理转换。
例如:
1.当我们输入Ctrl + D(或Z)时,shell会将该指令接受,并给行编辑填入EOF或-1(不同的电脑系统,对于shell填入不一样)。
2.对于填入的多个字符,如123,每次getchar只会读取一个字符交给putchar,但是剩下的字符会留在缓冲区等待下一次输出,直到缓冲区没有下一个字符读取时,才开始下一次读入输出。
六、字符串函数
strlen
形式:size_t strlen(const char *s);
作用:返回s的字符串长度(不包括结尾的0)。
使用方法:
法一:(利用变量储存长度)
法二:(直接输出长度)
其中也可自己定义一个与strlen函数作用相同的函数。
如:
strcmp
形式:int strcmp(const char *s1,const char *s2);
作用:比较两个字符串,返回:
0:s1==s2
1:s1>s2
-1:s1<s2
作用原理:
在字符串数组s1与s2里,前三个的字符相等,第四个字符的Ascll值,l<m,因此返回值为-1(尽管第五个字符o>m,且s1的字符和的Ascll码值大于s2,依然返回为-1)。
Ps:不同的电脑处理器,对应的返回值可能不一样,例如视频中翁恺老师演示的返回值为二者Ascll码差值,而本人试验后发现返回值依然为1,0,-1这三个数字,具体原因与编译器处理有关。)
同样的,也可自己写出一个与strcmp函数作用相同的函数。(如果想更改返回值为-1、0、1的话,只需要在最后加入判断并返回即可)
如:
法一:(利用数组形式)
法二:(利用指针形式)
strcpy
形式:char *strcpy (char *restrict dst , const char *restrict src);
(其中restrict表示src与dst不重叠( C99里的关键词))
(为了避免掩盖dst的内容,从而提高运行效率(与多核线程有关))
作用:1、把src的字符串拷贝到dst中;
2、为了能链起代码。
返回值:返回dst。(以便将结果用于继续做其他运算)
同样,也可制作类似效果的函数。(仅制作简单的拷贝字符串)
如:
法一:(利用数组形式)
法二:(利用指针形式)
精简版:(最终编译效果可能一样)
strcat
形式:char *strcat (char *restrict s1,const char *restrict s2);
作用:把s2拷贝到s1后面,接成一个长的字符串。
返回值:返回s1。
条件:s1必须有足够空间。
同样的,也可制作具有类似效果的函数。
如:
但使用strcpy跟strcat时,可能出现安全问题,如无空间时会出现越界。因此尽量使用安全版本。
strcpy的安全版本:
strncpy
形式:char *strncpy (char *restrict dst ,const char *restrict src ,size_t n);
其中n代表最多拷贝的上限。
strcat的安全版本:
strncat
形式:char *strncat (char *restrict s1,const char *restrict s2,size_t n);
其中n同样代表最多拷贝的上限。
strcmp也有带n版本,但目的不为了安全,为了减少判断数
strncmp
形式:int strncmp (const char *s1,const char *s2,size_t n);
其中n代表只判断前n个。
strchr和strrchr
strchr
形式:char *strchr (const char *s,int c);
作用:在s中从左往右找c所在的位置。
返回:如果存在,返回指针(指向该字符地址);如果没有,返回NULL。
strrchr
形式:char *strrchr (const char *s,int c);
作用:在s中从右往左找c所在的位置。
返回:如果存在,返回指针(指向该字符地址);如果没有,返回NULL。
二者区别仅在于从左开始还是从右开始。
套路一:寻找第二甚至其他地方的字符位置时,可以将第一个字符返回值加一。
如:
此时最后一个p对应的地址便是第二个l的地址。
套路二:进行拷贝字符串的部分内容时,可以通过改变其中字符为’\0’,最后恢复回去。
如:
其中利用C来储存原先的字符,最后在还原回去即可。
strstr与strcasestr
strstr
形式:char *strstr (const char *s1,const char *s2);
作用:在字符串s1中里找一个字符串s2。
strcasestr
形式:char *strcasestr (const char *s1,const char *s2);
作用:寻找字符串时,忽略大小写(其他作用与strstr相同)。