一、数组、字符串基本概念
数组定义:由同一种类型、有序数据的集合;各数据称作元素,在内存中占据一段连续的存储单元;一般经常使用的是一维数组、二维数组;数组名就是这一数组在内存中的首地址;
一维数组的使用:元素只能逐个引用;下标越界编译器并不检查,这个检查交给程序员自己;数组元素的下标必须是方括号;可利用for循环为数组初始化复制及引用;
当数组被说明静态(static)存储类型时或者外部存储类型(即在所有函数外部定义时,)则在不显示给出初值的情况下,数组元素将在程序编译阶段自动初始化为0;
static int a[4] 等价于 static int a[4]={0,0,0,0};
二维数组的使用:存在行指针与列指针,但是不是二级指针,且二维数组在内存中是按照行接行的形式存储的;第一维长度在初始化时可以不指定长度,但是第二维不能省略;
数组名作为实参传递给调用函数的形参属于地址调用;
当实参把主函数的变量的地址传递给形参(指针)时,才可以在被调用函数中修改主函数中该变量的值,才能带回修改值;因为形参和实参两个数组或者变量指针()在内存中因指向同一地址,操作的是同一个内存空间造成的;
初始化一维字符数组时,可以省略数组长度,系统会自动根据初值个数确定数组长度;
连续输出字符数组时,需要利用for循环连续输出单个字符;
因为C语言没有字符串类型,所以将字符串作为字符数组处理;第一个结束标志‘\0’前的字符成为有效字符串;字符串存储在数组中才可以修改,并且该数组的名字就是该字符串的首地址;当把字符串的地址交给一个单独的指针时,无法通过该指针修改字符串,因为指针只是有字符串的首地址,并没有提供存储空间,此时字符串是一个“字符串常量”,无法修改,存储在内存的常量区;也就是说这个字符串常量本身代表的是该字符串在内存中的首地址,也就是一个地址常量;
记住:声明一个数组将为数据分配存储空间,而声明一个指针只为一个地址分配存储空间,无法存储数据;
char c[]={"I am happy}; //正确,可修改字符串
char c[]="I am happy"; //正确,可修改字符串
char *p="I am happy"; //正确,只是该字符串是常量,无法通过指针修改,只可以打印;
字符串输出puts自带换行输出功能;
字符串输入gets可将空格等读入,直到\n;
二、字符串函数(string.h)
字符串输入输出
①scanf("%s",name); 缺点:无法跳过' ' ,即遇到空格就停止读入,导致后面的无法被读入到数组中;会在最后自动添加'\0'作为结束标志;适用于混合类型数据的读取和转换;
②ptr=gets(name); 最常用,优点是会自动跳过空格等,直到遇到换行符(即键盘的换行),并在最后自动添加'\0'作为结束标志;缺点是不检查输入的字符个数,可能超过数组总长度,导致越界;其返回值是字符串的地址(即数组的地址)返回给调用它的地方(交给指针ptr);
③ptr=fgets(name,MAX,stdin); 专用为io文件设置,为了避免gets的越界问题,fgets需要输入第二的参数(说明最大读入字符数,则实际存储的是MAX-1个,因为最后留一个给‘\0’)、第三个参数(说明从哪里读文件,如果是键盘,则使用stdin);需要注意的是fgets会存储‘\n’,然后最后是‘\0’,导致后续输出时,会输出一个换行符;所以如果后面利用printf输出是,后面就不用加‘\n’,如果使用puts输出将会导致连续两个换行;
④printf("%s\n",name); printf不会自动换行,需要添加一个'\n',适合于多种数据类型的格式化输出;
⑤puts(name); 会输出字符串后自动添加一个‘\n’;
⑥fputs(name,stdout); 面向io文件,stdout是标准输出(屏幕);注意他不会为输出添加换行符,一般配合fgets使用(因为fegets存储了换行符);
⑦循环方式:putchar, getchar 注意循环使用;
输入 | 输出 | 配合原因 |
scanf | printf | 多种类型形式混合,面向单词 |
gets | puts | 使用方便,前者不存储\n,后者自带\n |
fgets | fputs | 面向io文件,可指定输入个数,前者存储\n,后者不带\n; |
功能性字符串函数
函数 | 格式 | 功能说明 |
strlen | strlen(name) | 得到字符串的长度,不包括‘\0’,但是包括空格、制表符等; |
strcat | strcat(name1,name2) | 将第二个字符串拷贝到添加到第一个字符串的结尾,同时将自己最后的‘\0’也同步复制过去,但是不检查第一个数组的剩余空间是否足够,存在越界的可能; 返回值是第一个字符串的地址; |
strncat | strncat(name1, name2, num); | num是第三个参数表明第一个数组最多可以容纳多少个字符,注意第一个数组的‘\0’位置是要被第二个数组的字符覆盖掉的; 返回值是第一个字符串的地址; |
strcmp | strcmp(name1, name2); | 字典式比较两个字符串,若相同则返回0,若第一个字符串的ansii码小于第二个字符串,则返回-1,否则返回1; ansii中先显示大写字母(A65),后显示小写字母(a97),两者相差32; 返回值是int(-1,0,1) |
strncmp | strncmp(name1, name2, num); | num限定了比较两者的前几个字符,设置了范围;其他同上; |
strcpy | strcpy(name1, name2); | 将字符串2赋值或者复制到字符串1; |
strncpy | strcpy(name1, name2,num); | num是数组1可接受的最大的字符数,其他同上; |
sprintf | sprintf(name, "%s,%s,%d\n",str1,str2,num) | 把几个元素组合成一个字符串,例如将两个字符串、数字合并为一个字符串放到数组name中,而不是输出到显示屏上; |
strlwr | strlwr(name) | 将字符串中的大写字母转换为小写字母,同时将name的指针返回 |
strupr | strupr(name) | 将字符串中的小写字母转换为大写字母,同时将name的指针返回 |
三、指针基础知识
直接寻址:直接按变量名来获取变量内容的访问方式;&a;
专门用于存放地址型数据的变量就是指针变量;
间接寻址:通过指针变量来间接存取它所指向的变量的访问方式称为间接寻址;int *p=&a;
指针的作用:
①指针提供通过变量地址访问变量的手段;增加了间接寻址方式;
②指针为c的动态内存分配系统提供了支持;
③指针为动态数据结构(例如 链表、队列、二叉树等)提供支持,操作系统的编写;
④指针可以改善某些子程序的效率;(传指针参数在调用函数里面就可以直接修改主函数中的对应变量,不需要将该变量的整体数据传到调用函数中);
int *p=&a; int等类型是指针的基类型,说明指针可以指向这种类型的变量;
指针变量必须先定义(必须有地址交给它)再使用,否则会造成野指针;
运算符*和++、--优先级等同,连续运算,采用右结合。下列各语句的含义如下:
a=*p++ 先运算p++,但为后增运算,因而先将*p的值赋给a,然后p加1。
a=(*p)++ 先取*p的值,赋给a。然后将p所指向的变量内容加1。
字符指针:就是指向字符型数据的指针变量;可以指向字符串;
字符数组可用于存放字符串,直接通过数组元素存取字符串属于直接寻址,字符指针则属
于间接寻址。
字符指针作为函数参数传递给形参,那么就可以在调用函数中修改其指向的变量的值;
在表达式中,数组名被自动转化为指向数组中第一个元素的常量指针;
利用指向字符串的指针的自增运算(++、--)可以逐个访问各元素,遍历;
四、指针数组
由若干基类型相同的指针所构成的数组。一个数组,其元素均为指针的数组;但是这种不是二维指针;
主要作用:适用于用来指定若干个字符串,使字符串处理更加灵活;
五、动态数据结构
静态数据结构—数组对于数据个数变化 较大时,存储空间浪费很大。是由于在编译时,数组元素的存储空间已分配
动态数据结构—结点对于数据个数变化较大时,存储空间得到100%的利用,是由于在编译时,不分配结点的存储空间,需要时,临时申请,系统再分配存储空间。
动态存储分配函数头文件:malloc.h/stdlib.h;
malloc()函数
①在内存的动态存储区中分配一个长度为size的连续空间;
②此函数的返回值是一个指向分配域的起始地址指针 (基类型为void,可以在前面强制转换) 。如果此函数未能成功地执行,则返回空指针。
③例子:
long *p;
p=(long *)malloc(8);
//申请一个8个存储字节的空间,
//并将其返回的指针转换成长整形指针。
calloc()函数
①格式:void *calloc(unsigned int n, size) 其中n是一共几个数据,size是每个数据所占字节数;
②
long *p;
p=(long *)malloc(5, 4);
③其他同malloc()函数;
free()函数
①作用:释放由p指向的存储区,使这部分存储区归还给系统,以便再分配。
②
long *p;
p=(long *)malloc(5, 8); //申请
…… //使用
free(p); //释放
relloc()函数
①作用将p指向的存储空间大小改为size个字节,扩大或缩小原存储空间;就是说前面malloc()或calloc()函数分配的空间在运行中过大或过小,利用realloc()函数更改空间大小;
②
char *p;
p=(char *)calloc(5, 8);
……
p=realloc(p, 10); //将元素的个数增加到10个;
……
free(p)
③函数的返回值是新的存储空间的首地址,与原首地址不一定相同。若不一致,该函数会把原来的数据同步复制到新的空间里面,不会造成数据丢失;