C语言的琐碎记录——读《C和指针》
1. 关于数组长度
数组可以指定长度然后初始化,也可以由编译器自动根据初始化内容计算数组长度
int vector[5] = {1, 2, 3, 4, 5};//指定长度初始化
int vector[] = {1, 2, 3, 4, 5, 6};//自动计算数组长度
对于字符形式,可以直接指定初始化,也可以使用字符串的方法初始化
//1
char message1[] = {'H', 'e', 'l', 'l', 'o'};
//2
char message2[] = "Hello";
char *message3 = message1;
注意message1和message2的内容是不一样的,1的方式长度为5,2的方式长度为6,多了一个'\0',下边的这种初始化方式其实经常被用到。
对于下面的这种类型其实是可以看做字符串,库函数里有标准获取字符串长度的函数strlen(),但是得到的结果是5,不包括最后的结束符'\0',也就是说你把它看做字符串时,统计字符长度strlen只统计字符个数。
统计数组的长度并没有标注库函数,C语言惯用的获取数组长度采用下面的宏定义
#define ARRAY_LEN(array) \
(sizeof(array)/sizeof(array[0]))
这里将message2传进去得到的结果是6,可以使用message1计算,但不能将message3传进去。
2.关于多维数组作为函数参数
假设要调用一个矩阵:
int matrix[3][10];
...
func(matrix);
这里参数matrix的类型是指向包含10个整形元素的数组的指针,func的原型可以是以下的任一种:
void func(int (*mat)[10]);
void func(int mat[][10]);
其中第二维长度必须声明,使用下面的声明是不正确的:
void func(int **mat);//mat是指向整形指针的指针
3. 关于size_t
stddef.h定义size_t是一个无符号整形,很多函数返回的是size_t类型,比如strlen,注意其是无符号的
if(strlen(x) >= strlen(y)) ...
if(strlen(x) - strlen(y) >= 0) ...
以上两个表达式是不一样的,第二条语句结果永远为真,如果使用第二种方式注意强转为int可消除问题。
4.字符串函数的一些问题
常用的字符串函数都是“不受限制”的,即只通过寻找字符串结尾的'\0'字节来判断它的长度,比如:
a. strcpy、strcat必须保证目标字符数组的空间足以容纳源字符串,否则出错
b. strcmp的返回结果有三种:小于、等于、大于,判断是否相等的比较好的判断风格如下:
if(0 == strcmp(a, b))
注意比较的字符串参数必须以'\0'结尾。
上面的问题在库函数有长度受限的字符串函数:
strncpy、strncat、strncmp,这些是安全的字符串函数,防止长字符串从它们的目标数组溢出,自己使用的时候尽量使用这些函数,避免大量调试工作,
其中要注意strncpy,如果源串大于目标串的长度,目标的结果将不会以'\0'结束。为了保证是一个完整的串,可以使用下面的方法:
char buffer[BSIZE];
...
strncpy(buffer, name, BSIZE);
buffer[BSIZE-1];
name可以容于buffer的时候,最后的赋值语句没有作用;但当name太长超过BSIZE大小时,最后的赋值语句可保证buffer中是字符串。可以考虑把后面两句自己打包为一个宏进行调用。