伍
***字符串***
字符串是一种特殊的数组类型。字符串必须用’\0’作为结束标识。’\0’占用存储空间,但不计入串的实际长度。
***字符串的初始化:***(编译器会自动在其尾部添加’\0’标识)
~~~
char str[] = {‘a’, ‘b’, ‘c’} ; //标准形式
char str[] = {“abc”} ; //简写
char str[] = “abc” ; //最简写
注意:
char a[3] = “abc” ; //在C中是合法的。但其不是字符串,它没有把’\0’存入。(C++中非法)
char a[3] = “abcdefg”; //也是合法的,但会产生警告。编译器会只取前三个字符放到数组中
int a[3] = {1,2,3,4,5}; //是非法的。
~~~
char a[] = “abcd” ; 与 char * p = “abcd” ; 的区别
***字符串字面量:***(也称字符串常量,即形如“abcd”的)**
①当作为数组初始值时,它指明该数组中字符的初始值。(只是定义字符串的一种简写形式)
②在其它情况下,它会转化为一个无名字符数组的首地址,且此字符数组存储在内存中的只读常量区中,这就导致它不能被修改。
故:上面,a[]是个字符串数组,而p是指向字符串首字符的指针。
例:”xyz”+1 的结果为:指向第二个字符的指针值
“xyz”[2]的结果为:字符z (方括号是一个后缀表达式的操作符)
注意:
ASCI C引入的另一个新特性是,**相邻的字符串常量将被自动合并成一个字符串。**
这样,后续的字符串也可以出现在每行的开头。
***字符数组:***
char laguage[3][10] = {“BASIC”, “C++”, “JAVA”};
//数组的第一个下标决定了字符串的个数,第二个下标是字符串的最大长度。
//其在内存中开辟了一个 3*10*sizeof(char)大小的存储区。
//由于字符串有长有短,故用数组会浪费一定的存储空间。
***字符指针数组:***
char *p[] = {“BASIC”, “C++”, “JAVA”} ;
p是由三个字符指针组成的数组。这三个指针分别指向只读区的三个无名字符串的首字符。
//字符指针数组可用于:单词的检索表。**
// char *p[] = {“BASIC”, “C++”, “JAVA”,NULL} ;若在表的末尾增加一个NULL指针作为结束标志,则可使在检索的时候能检测到表的结束,而无需预先知道表的长度。
***常用的字符串处理库函数陷阱:***
**函数strlen( )的返回值是size_t**,这个类型是在头文件stddef.h中定义的 是unsigned int 类型的别名。 故使用时一定要注意,隐私类型转换可能产生的错误!
例: if(strlen(s1) – strlen(s2) >= 0 ) {........}
表达式的左边的结果是无符号数,根据值的类型转换提升规则,右边的int型0会提升为无符号数。而无符号数是绝不可能为负的。故这个条件判断永远为真。
【为避免混用有符号数和无符号数 可能产生的问题,**在使用strlen( )时,设一个int型的变量来接收strlen( )的返回值,可避免错误。**】
**函数strncpy( )的结果将不会自动以’\0’字节结尾!你必须自己给结果字符串添加’\0’ 字节。**
函数strncat( )的结果会自动添加’\0’字节。(故:我们可把目的字符串先置空,然后就可用strncat( )来代替strncpy( )的功能 )
***函数***
***关于函数返回值***
**当设计函数返回指针时,一定要警惕!检查其返回指针的类型。被调函数绝对不能返回本局部变量的指针**,(因为函数返回后其开辟的运行时栈,被回收,其中所有的局部变量被抛弃,返回它们的指针是无效的)。
函数返回的指针可以是:
①静态分配的缓冲区。例:全局变量的指针 【少用】
②调入者传入的缓冲区。(在主调函数中) 【常用】
③用malloc()获得的内存 【记得要在不用的时候释放】
***主函数***
ANSI标准C规定了主函数的两种形式:
int main(void) ;
int main(int argc, char **argv) ;
main( )所需的实参是在命令行与程序名一同输入的。程序名和各实参之间用空格分隔。
格式为:含路径的可执行程序名 参数1 参数2 ......参数n
形参argc 为命令行中参数的个数(包括执行程序名)其值大于等于1。
形参argv为一个二级指针 指向一个指针数组的首元素,这个指针数组中的元素依次指向命令行中以空格分开的各参数字符串。(即第一个指针argv[0]指向的是程序名字符串,argv[1]指向的是参数1,......)
***可变参函数***(让函数可以接受不定数目的参数)
可变参数列表是通过宏来实现的,这些宏定义于stdarg.h头文件中,这个头文件声明了一个类型 va_list 和三个宏 va_start va_arg va_end
~~~
//计算不定数量值的平均值
#include <stdarg.h>
//注意:可变参数的类型必须保持一致!
double Average(int num, ...) //参数:第一个num为后面参数的个数,不定参数用3个点来表示。
{
va_list values ; //values是一个参数列表类型。其中包含着所有的不定参数。
int cnt=0 ;
float sum=0 ;
/*准备访问可变参数*/
va_start( values, num ) ; //初始化参数列表变量values
for(cnt=0; cnt < num; cnt++)
sum += va_arg( values, double) ; // double指明参数列表中参数的类型,每调用一次此语句此宏表示的参数就顺移到下一个参数。(如此,可顺序地处理每个传入的参数)
/*结束访问可变参数*/
va_end( values ) ;
return sum/num ;
}
~~~
***内联函数:***
函数指定符inline只能出现在函数声明中,这种函数便成为内联函数。使用inline是向编译器所提供的提示,表示应该采用措施来提高这个函数的调用速度。即,对一个函数的调用将被该函数的一份拷贝所替代。(有点类似宏函数,但有区别)这就消除了函数调用的开销。
【注意,编译器并不一定要执行内联展开,C程序不能依赖于一个函数调用将被内联展开】
***动态内存分配***
【**勿忘:及时释放不再使用的动态分配的内存!**】
***几个库函数:***
void * malloc(size_t bit) ; //函数名意为:memoryallocation
void * calloc(size_t num, size_t bit) ; //函数名意为:cleanallocation
此函数在返回指向内存的指针之前 把内存中的值初始化为0
void realloc(void *ptr, size_t new_size) ;
此函数用于修改一个原先已经分配的内存块大小。
①用于扩大内存块。(新增内存添加到原先内存块的后面)
②用于缩小内存块。(内存块的尾部部分被拿掉,剩余的内存内容保留)
③若原先内存块的大小无法改变,则recalloc重新分配新内存,并复制原先内容。
【故在使用realloc函数时,通常不应该立即将新指针赋给就指针,最好用一个临时指针】
void free(void *ptr) ;
将指针ptr所指的动态存储空间释放。