有一种特殊的字符数组,它经常与字符串(常量)一起使用。
字符数组
字符数组的定义和操作可以与普通的数组一样,但有一些特殊性。
初始化
普通方法初始化:char s[10]={'h','e','l','l','o'}; 部分初始化,后面5个清0,也就是'\0'
通过字符串:char s[10]={"hello"}; 或者直接 char s[10]="hello"; 与普通的初始化方式结果一样,区别在数组长度要满足字符串所占空间,否则报错。 char s[5]="hello"; 是错误的,字符串有一个隐藏的字符串结束符'\0' ; char s[6]="hello"; 则是正确的。
字符数组输入
普通方法通过for循环
其中:getchar 、putchar 是C语言的字符输入输出函数。与scanf返回成功输入项个数不同,getchar 返回值为用户输入的ASCⅡ码。
C语言的两个函数把空格、换行等分割符看成了输入的一个字符:
C++的cin两种情况都可以完成输入:
整体方法
输入输出也可以整体完成了(其他类型数组不行):
同样要注意字符数组的大小问题。
scanf、printf可以使用新的格式字符 % s
定义宏解决非安全问题,scanf 输入项不需要 & (取变量地址)
gets、puts也可以完成输入输出,与scanf、printf稍有不同:puts遇到 '\0' 换行(字符串结束换行)
gets可以完成空格字符的读入,scanf不行
二维字符数组
二维字符数组在对多个字符串的处理种经常应用:
gets、puts、scanf、printf也可以完成相应的工作。
数组地址
更深入了解数组的地址,对程序设计中空间分配、管理会有更深的理解。在scanf函数的输入项需要在变量前加"&"符号,这就是取地址的运算符。
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
int x[10],y[10][10];
cout<<"一维数组x的首地址: "<<x<<endl;
cout<<"一维数组x下标为0的地址:"<<&x[0]<<endl;
cout<<"一维数组x下标为5的地址:"<<&x[5]<<endl;
cout<<"首地址+5的算术运算: "<<x+5<<endl;
cout<<"**************"<<endl;
cout<<"二维数组y的首地址: "<<y<<endl;
cout<<"二维数组y的0行0列地址:"<<&y[0][0]<<endl;
cout<<"二维数组y的1行5列地址:"<<&y[1][5]<<endl;
cout<<"二维数组y的0行地址:"<<y[0]<<endl;
cout<<"二维数组y的2行地址: "<<y[2]<<endl;
cout<<"首地址 + 2 :"<<y + 2<<endl;
cout<<"1行地址 + 5 : "<<y[1] +5<<endl;
return 0;
}
注意(输入默认十六进制):
1、一维数组首地址与第一个元素(下标为0)的地址是相同的;
2、一维数组的首地址 + 5,并非整数的加法,而应该是加上 5 个元素 5*4=20个字节;
3、二维数组虽然物理存储还是一维结构,但是具有二维特性:行地址的概念,y[0]、y[2]分别代表第0行、第2行的首地址;
4、二维数组名进行加法运算,则是加上几行,这个很重要,y+2 === y[2]
5、二维数组第 i 行 第 j 列元素的地址,应该写成:y[i]+j 或者 &y[i][j] ;还有一种写法是:
*(y+i) +j ;
* 是取内容操作符,与取地址 & 相反,*是根据地址 去取出 该地址保存的值。上面的操作则可以理解为:先取出y数组的第i行首地址 ,再偏移j个元素,也就是第 i 行 第 j 列。
更让人惊讶的就是:
它们完全相同!
首先:一个内存空间能不能存放内存的编号(内存地址)?当然可以,在编号****位置存上值****是可以的,那么****的地址和内容是不是一样? 所以,地址和内容相同是可以的;
然后:为什么这么做?不这样设计语法,肯定让 + 等运算出现歧义,到底是一维数组名还是二维数组名在物理存储来看并没有区别,物理内存空间永远都是一个一维的存储格式,内存地址从32个0 ~ 32个F (32位内存空间)。
所以,为了保留二维数组的行列结构特点,引入行地址的概念来解决这个问题。可以查询更多的资料进行深入地探讨这个问题。
字符串库函数
在C语言中,string.h 包含了很多字符串处理函数,包括strcpy、strcat、strcmp、strlen等等,可以参考相应的资料;注意几点:
1、比较字符数组内容strcmp 和 关系运算符== 是不同的概念,但是字符串常量是存放在常量存储空间的,有时候==又与strcmp具有相同的功能(相同地址当然内容也相同)。
2、strcat要注意合并的长度不要超过字符数组大小
3、strlen不包括'\0',与sizeof 求数组字节( 数组所占空间的大小)
C++提供了string的 新数据类型,应该属于STL的内容,在ACM里再说。