十一、字符串和字符串函数
1、用双引号括起来的内容称为字符串常量,双引号中的字符和编译器自动加入末尾的\0字符,都作为字符串存储在内存中。如果要在字符串内部使用双引号,必须在双引号前面加上一个反斜杠( \ )。
2、用双引号括起来的内容被视为指向该字符串存储位置的指针,这类似于把数组名作为指向该数组位置的指针。
3、递增运算符(++)只能用于变量名前(即只能用于可修改的左值)。
4、初始化数组是把静态存储区的字符串拷贝到数组中,而初始化指针只把字符串的地址拷贝给指针。
5、数组的元素是变量(除非数组被声明为const),但数组名不是变量,是地址。
6、如果要用数组表示一系列待显示的字符串,使用指针数组,因为它比二位字符数组的效率高,但数组中的指针指向的字符串常量不能更改。
如果要改变字符串或为字符串输入预留空间,不要使用指向字符串常量的指针。
7、gets()函数可以整行输入,但它只知道数组的开始处,并不知道数组中有多少个元素。如果输入的字符串过长,会导致缓冲区溢出,即多余的字符超出了指定的目标空间。如果这些多余的字符只是占用了尚未使用的内存,就不会立即出现问题;如果它们擦写掉程序中的其他数据,会导致程序异常中止。
8、fgets()函数和fputs()函数替代gets()和puts()函数:fget()函数通过第2个参数限制读入的字符数来解决溢出的问题。fgets()函数的第2个参数指明了读入字符的最大数量,第3个参数指明要读入的文件(如果读入从键盘输入的数据,则以stdin—标准输入,作为参数)。fputs()函数的第2个参数指明它要写入的文件,如果要显示在显示器上,使用stdout(标准输出)作为该参数;puts()函数会在输出末尾添加一个换行符,fputs()函数则不会。
9、空指针和空字符
空字符(或‘\0’):是用于标记C字符串末尾的字符,其对应编码是0。由于其他字符的编码不可能是0,所以不可能是字符串的一部分。
空指针(或NULL):是一个值,该值不会与任何数据的有效地址对应。通常,函数使用它返回一个有效地址表示某些特殊情况发生,例如遇到文件结尾或未能按预期执行。
空字符是整数类型,而空指针是指针类型。两者容易混淆的原因是:它们都可以用数值0来表示。但是,从概念上看,两者是不同类型的0。另外,空字符是一个字符,占1字节;而空指针是一个地址,通常占4字节。
10、gets_s()函数:用它代替gets()函数,它只从标准输入中读取数据,所以不需要第3个参数。
11、字符串函数:
①strlen()函数:统计字符串的长度;
strlen("hello") is 5
②strcat()函数:接受两个字符串作为参数,把第2个字符串的备份附加在第1个字符串的末尾,并把拼接后形成的新字符串作为第1个字符串,第2个字符串不变。
strcat("hello " , "world") is "hello world"
③strncat()函数:由于strcat()函数无法检查第1个数组是否能容纳第2个字符串,如果分配给第1个数组的空间不够大,多出来的字符溢出到相邻存储单元时就会出问题。可以用strncat()函数替代,该函数的第3个参数指定了最大添加字符数。
strncat("hello " , "world" , 6) is "hello world"
④strcmp()函数:该函数通过比较运算符来比较字符串,就像比较数字一样。如果两个字符串参数相同,该函数就返回0,否则返回非0值。如果第1个字符串位于第2个字符串前面,strcmp()返回负数;反之则返回正数。
strcmp("A" , "A") is 0
strcmp("A" , "B") is -1
strcmp("apples" , "apple") is 1
⑤strncmp()函数:strcmp()函数比较字符串中的字符,直到发现不同的字符为止,这一过程可能会持续到字符串的末尾。而strncmp()函数在比较两个字符串时,可以比较到字符不同的地方,也可以只比较第3个参数指定的字符数。
⑥strcpy()函数:相当于字符串赋值运算符,它第2个参数指向的字符串被拷贝到第1个参数指向的数组中。
⑦strncpy()函数:拷贝字符串用strncpy()更安全,该函数的第3个参数指明可拷贝的最大字符数。
⑧springf()函数:该函数声明在stdio.h中,而不是string.h中。该函数和printf()函数类型,但是它是把数据写入字符串,而不是打印在显示器上。
十二、存储类别、链接和内存管理
1、块作用域变量 = 局部变量 ;
文件作用域变量 = 全局变量 。
2、malloc()函数可用于返回指向数组的指针、指向结构的指针等,所以通常该函数的返回值会被强制转换为匹配的类型。
ptd = (double *) malloc(n * sizeof(double));
3、通常malloc()函数要与free()函数配套使用。free()函数的参数是之前malloc()返回的地址,该函数释放之前malloc()分配的地址。因此,动态内存分配的存储期从调用malloc()分配内存到调用free()释放内存为止。
4、内存泄漏:指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。在函数末尾处调用free()函数可避免这类问题发生。
5、calloc()函数:该函数接受两个无符号整数作为参数,第1个参数是所需的存储单元数量,第2个参数是存储单元的大小(以字节为单位)。free()函数也可用于释放calloc()分配的内存。下例中,long是4字节,所以前面的代码创建了100个4字节的存储单元,总共400字节。
long * nuwmen;
newmen = (long *)calloc(100, sizeof (long));
6、以const关键字声明的对象,其值不能通过赋值或递增、递减来修改。
const放在 * 左侧任意位置,限定了指针指向的数据不能改变;const放在 * 的右侧,限定了指针本身不能改变。
十三、文件输入\输出
1、文本模式和二进制模式:所有文件的内容都以二进制形式(0或1)存储。但是,如果文件最初使用二进制编码的字符(如ASCII)表示文本,该文件就是文本文件,其中包含文本内容。如果文件中的二进制值代表机器语言代码或数值数据(使用相同的内部表示)或图片或音乐编码,该文件就是二进制文件,其中包含二进制内容。
2、为了规范文本文件的处理,C提供两种访问文件的途径:二进制模式和文本模式。在二进制模式中,程序可以访问文件的每个字节。而在文本模式中,程序所见的内容和文件的实际内容不同。
3、标准I\O中,输入和输出都是缓冲的,即一次转移一大块信息而不是一字节信息(通常至少是512字节)。
4、fopen()函数:该函数声明在stdio.h中。它的第1个参数是待打开文件的名称,即一个包含该文件名的字符串地址。第2个参数是一个字符串,指定待打开文件的模式。程序成功打开文件后,fopen()返回文件指针。
5、fclose()函数:如果成功关闭,fclose()函数返回0,否则返回EOF。