其他分享
首页 > 其他分享> > 第十一章:字符串和字符串函数

第十一章:字符串和字符串函数

作者:互联网

字符串和字符串函数

gets()、 gets_s()、 fgets()、 puts()、 fputs()、 strcat()、 strncat()、strcmp()、 strncmp()、 strcpy()、 strncpy()、 sprintf()、 strchr()

一、字符串是C语言中最常用,且最有效的数据类型之一。读写字符串、比较字符串、合并字符串、查找字符串。

11.1表示字符串和字符串I/O

1、字符串是以空字符(\0) 结尾的char类型数组。
2、字符串的性质、如何声明、如何在程序中输入和输出字符串、以及如何操控字符串。
3、puts()函数,只显示字符串,只能打印字符串,而且自动在显示的字符串末尾加上/0。
定义字符串的方法:(即字符串常量、 char类型数组、 指向char的指针)定义字符串。
const char * pt1 = “Something is pointing at me.”;
字符串常量属于静态存储类别。这说明在函数中使用字符串常量,该字符串只会被存储一次,但是可以被无限次调用
用双引号括起来的内容,被视为指向该字符串存储位置的指针。这类似于把数组名作为指向该数组位置的指针。
4、字符串字面量:用双引号括起来的内容称为字符串字面量,也叫做字符串常量,双引号中的字符和编译器自动加入末尾的\0字符,都是作为字符串存储在内存中。 如果要在字符串内部使用双引号,那么必须在双引号前边加上一个反斜杠
5、还可以这样操作呀? printf("%s,%p,%c\n",“we”,“are”,*“space farers”);
输出: we,0x100000f61,s
----- "space farers"表示的是该字符串所指向低智商存储的值,也就是字符串"space farers"的首字符。
6、字符数组与字符串的区别在于末尾的\0.
比如:const char ma[4] = “abc”; const char ma[4] = {‘a’,‘b’,‘c’,’\0’}; 这两个等价,都是字符串
const char ma[4] = {‘a’,‘b’,‘c’};为字符数组。
7、在定义的字符串中,未被初始化的部分会自动被初始化为char类型的字符0(char形式的空字符),而不是数字字符0.
8、让编译器计算数组的大小,只能在初始化数组的时候。
9、字符数组名和其他数组名一样,都是该数组首元素的地址。那么比如:char car[] = “Tata”;则有:
car == &car[0]; *car ==‘T’; *(car+1) ==&car[1] == ‘a’;
10、指针方法创建字符串:const char *ptr1 = “Something is pointing at me”;
思考:指针创建字符串是否预留空间了?而数组创建字符串本身决定了预留给字符串的存储空间。
指针形式(*ptr1) 也使得编译器为字符串在静态存储区预留29个元素的空间。

11、数组和指针:

11.1、在采用段式内存管理的架构中,数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

11.2、数据段,代码段在程序运行之前就已经确定了的。

12、定义数组时,数组的大小自动时,大小是由编译器计算确定的。

定义数组,使用的时候,从内存中的特定区域拷贝数组到内存中。
++ 只能用于可修改的左值,而不能用于常量。数组名就不能++ 比如:++ar;

总之, 初始化数组把静态存储区的字符串拷贝到数组中, 而初始化指针只把字符串的地址拷贝给指针。

13、 #define :MSG I am specical
    int main()
    {
        char ar[] = MSG;  
        const char *pt = MSG;
    }
    //注意上边程序:ar的地址与pt的地址不同。因为初始化数组,是把静态区的数组拷贝到内存中了。
    //静态数据使用的内存与ar使用的动态内存不同。
编译器会将同一个常量存储到同一个位置。
定义了一个常量字符串,又定义了一个数组,给数组初始化成字符串。程序开始运行之后才会给数组分配内存,分配内存之后,才将字符串常量拷贝到内存中。常量字符串是存储于静态存储区的。在数组形式中,数组名是常量。
14、数组与指针的区别:P325
指针指向字符串:指向了字符串的首字符。而数组初始化字符串,数组名是常量,指针是变量。
(1):两者都可以用数组的形式来访问字符串;
(2):两者都可以使用指针加法 比如:*(heart+i)
(3):只有指针法才能使用++;也就是说只有变量才可以使用++;
15、数组的元素是变量,但是数组名是常量。
 编译器可以使用内存中的一个副本来表示所有完全相同的字符串字面量。
 如果不修改字符串, 不要用指针指向字符串字面量    
16、指向字符串的指针数组与char类型数组的数组。P327
char *pointarray[] =
{
};

#define SLEN 40
#define LIM 5    
const char *mytalents[LIM] = {
        "Adding numbers swiftly",
        "Multiplying accurately", "Stashing data",
        "Following instructions to the letter",
        "Understanding the C language"
        };
        
char yourtalents[LIM][SLEN] = {
        "Walking in a straight line",
        "Sleeping", "Watching television",
        "Mailing letters", "Reading email"
        };
sizeof mytalents: 40, sizeof yourtalents: 200
mytalents数组是一个内含5个指针的数组, 在我们的系统中共占用40字节。 而yourtalents是一个内含5个数组的数组, 每个数组内含40个char类型的值,共占用200字节。
mytalents中的指针指向初始化时所用的字符串字面量的位置, 这些字符串字面量被储存在静态内存中; 而 yourtalents 中的数组则储存着字符串字面量的副本, 所以每个字符串都被储存了两次。 此外, 为字符串数组分配内存的使用率较低。 yourtalents 中的每个元素的大小必须相同, 而且必须是能储存最长字符串的大小。
17、指针指向字符串常量与数组的数组存储字符串常量的区别与优势:指针指向的不可修改,如果要直接显示那么用指针数组,如果要改变或为字符串输入预留空间,则用数组。 P328图。
18、如何从键盘输入字符串?
(1)如果要想把一个字符串读入程序,首先必须预留存储该字符串的空间,然后用输入函数获取该字符串。P
(2)C库提供了很多获取字符串的函数:比如:scanf() gets() fgets()   【到这里的时候就要联想到put()函数的用法】
(3)sanf()函数与%s只能读取一个单词,而gets()函数可以读取一整行输入,直到遇到换行符,丢弃换行符,存储其他的字符,并且在末尾添加一个空字符,使其构成字符串 。gets()函数 容易造成越界之类的问题,使用不当的话。
(3.1)gets()函数读取整行输入,直至遇到换行符,然后丢弃换行符,存储其余字符,并在末尾添加一个空字符使其成为字符串,该函数经常与puts()函数配合使用,puts()函数,用于显示字符串,并在末尾添加换行符。
(4)fgets()和fputs()
 fgets()函数有三个参数:第二个参数指明了读入字符的最大数量,如果此值是n,那么此函数读到n-1个字符就停止,或者读到遇到的第一个换行符。
                        如果fgets()函数遇到第一个换行符,它会把这个换行符存入字符串中,这个与gets()函数不同,gets()会丢弃。
                        第三个参数指明了要读入的文件。
 puts()函数会在末尾自动加上换行符,而 fputs()不会。
(5.1)fgets()函数把换行符放在字符串的末尾(假设输入行不溢出),通常要与fputs()函数配对使用。
fgets(数组名,数组大小,stdin(标准输入));   fputs(数组名,数组大小,stdout(标准输出));
fgets()函数返回指向一个char类型指针。如果一切顺利,该函数返回的地址与传入的第一个参数的地址相同。也就是数组首元素地址。但是如果函数读到文件结尾,它将返回一个特殊的指针:空指针(NULL)
(5)P333 fgets()函数的理解。。假如往一个数组中读入(标准输入,从屏幕缓冲区中输入)一个字符串,然而输入的字符串的长度超过了数组可以存储的长度,以数组长度-1为单位一次一次读入。
(6)fgets()函数存储换行符有好处也有坏处。坏处:不想要但被存入了。好处:可以作为检查字符串是否读到末尾。
(7)while(getchar() != '\n') //读取但不存储输入,包括\n.
19.continue的用法:联系break:两个都可以根据循环体中的测试结果来忽略一部分循环内容,甚至结束循环。
3种循环都可以使用continue语句。执行到该语句时,会跳过本次迭代的剩余部分,并开始下一轮迭代,如果continue嵌套在循环内,则只会影响包含该语句的内层循环。break就是结束当前的部分,跳到下一部分开始执行。
20、空字符(’\0’)空指针(NULL)的区别:从概念上来讲,两者根本就不同,空字符用于标记字符串的结尾,其对应的编码值为0.由于其他字符的编码值不可能为0,所以不可能是字符串的一部分。空指针(NULL)有一个值,这个值不会与任何数据的有效地址对应。通常,函数利用它返回一个有效地址表示某些特殊情况的发生,例如遇到文件结尾或未能按预期执行。

空字符是整数类型,空指针是指针类型。两者容易混淆的原因是:它们都可以用数值0来表示。但是概念上,两者是不同类型的0.空字符占1个字节,空指针占4个字节。

21、P334中的函数中的else不好理解。。。
22、getchar() putchar()都不是正在的函数,而是供预处理器使用的宏。 ch = getchar()和scanf("%s",ch)功能相同。
23、gets_s()函数:与fgets()函数的区别:
(1)gets_s只从标准输入中读取,因此不需要第三个参数,gets_(worsd,STLEN);
(2)如果gets_s读到换行符,就丢弃换行符,而不是存储换行符,而fgets会存储。
(3)如果fgets()读到最大字符数,没有读到换行符,那么会执行以下步骤:首先把目标字符中的首字符设置成空字符,读取并丢弃随后的输入直至读到换行或文件结尾,然后返回空指针。
24、scanf()函数:都是从第一个非空白字符作为字符串的开始。如果使用%s转换说明,以下一个空白符(空行、空格、制表符或换行符)作为字符串的介绍(字符串不包括空字符)。如果定义了字段宽度,如%10s,那么scanf()将读取10个字符或读到第一个空白字符就停止。scanf()函数返回一个整数值,该值等于scanf()函数成功读取的项数或EOF(读到文件结尾时返回EOF)。
11.3字符串的输出

1、C有三个标准库函数打印字符串:puts() fputs() printf()。

标签:函数,第十一章,char,数组,字符串,换行符,指针
来源: https://blog.csdn.net/Naunyang/article/details/122351488