我觉得定义字符数组是一件很玄学的事
(整型数组可以由此类推,这里就不单独讲解了)
虽然说网上有许多blog讲解,但是这里我还是想要做一个尽量全面的总结
我们在处理字符串的时候,最常用的两种数据类型就是 c h a r char char和 s t r i n g string string
众所周知, s t r i n g string string实际上就可以笼统的认为是一个一维char数组
string s="Hello world!";
那么我们怎么定义一个char类型的一维数组存储一个字符串呢?
下面我给出了三种方法:
char c[10]; //1
char *c1; //2
char c2[]; //3
方法一是中规中矩的定义了一个长度为10的一维数组(比较憨)
方法二本质上是定义了一个指针,因为数组名称实际上就是数组的起始地址
方法三定义了一个长度不定的字符串数组
而方法二和方法三,在实际应用中,一般都会在定义的时候提供对于c1,c2的初始化,根据初始值确定字符数组的大小
char *c1="like";
char c2[]="love":
如此定义,计算机会在字符串后自动添加结束符 ’ \0 ’ ,然后赋值给变量
那么方法二和方法三有什么区别嘛?
实际上是有的:
char *c="live";
c[1]='o';
//Wrong!Wrong!Wrong!
char c1[]="love";
c1[1]='i';
//Yes!Yes!Yes!
注意:指针式定义法无法用一般方法改变某个字符
指针式定义在编译时,会直接标记为const(指向常量字符串的指针)
下面我们就要面对二维字符数组的定义了
还是由浅入深,从 s t r i n g string string说起:
string s0[2]={"Hello","world"}; //憨憨定义,没意思
string s[]={"Hello","world"};
那么string类型的二维数组可以用指针定义嘛?
很遗憾,不可以:
下面就看一下比较复杂的char类型二维数组:
(我们将定义和初始化结合在一起讨论)
//1
char *c[2]={"aa","bb"};
//2
char *c[]={"aaa","bbb","ccc"};
//3
char c[][3]={"aa","bb"};
//4
char c[2][3]={"aa","bb"};
//5
char c[2][3]={{'a','a'},{'b','b'}};
//6
char c[2][3]={{'a','a','\0'},{'b','b','\0'}};
我在这里尝试对这些定义做出一些解释:
- 方法一:
定义一个行数为2,列数不确定的数组 - 方法二:
定义一个行数,列数均不确定的数组 - 方法三:
定义一个行数不确定,列数为3的数组
双中括号的定义方式,只能省略行数的定义
注意这里列数为3而不能再少了,是因为字符串结束符 ’ \0 ’ 必须占据一位 - 方法四:
精准定义二维数组大小,直接用字符串进行初始化 - 方法五:
精准定义二维数组大小,用单个字符串进行初始化,不添加末尾结束符 - 方法六:
精准定义二维数组大小,用单个字符串进行初始化,添加末尾结束符
如果我们想要在函数调用时,传递数组怎么办?
一维char类型数组的传递非常简单
以下的每种方法传递的都是引用,可以在函数中对数组进行修改
不过如果一开始定义的时候使用了指针式定义法,是不能单独修改字符串某位的
char c[]="live";
//这里如果用*c形式定义是不能进行修改的
void doit(char *c) {
c[1]='o';
cout<<c<<endl;
return;
}
输出:love
下面的两种方法也是可以成功进行上述操作的:
char c[]="live";
void doit(char c[]) {...}
void doit(char c[10]) {...}
重点看二维字符数组:
s t r i n g string string类型:传递引用
因为string类型定义的时候是不能使用指针形式的,所以以下两种传参方式都可以对字符数组进行 “ 本质修改 ”
string s[]={"aaa","bbb"};
void doit(string *s) { //这里可以是指针类型
s[0][0]='z';
for (int i=0;i<2;i++) cout<<s[i]<<endl;
return;
}
输出:
zaa
bbb
//以下同理
void doit(string s[]) {...}
c h a r char char类型:
首先让我再次强调一遍:如果使用指针式定义,不能单独修改某一位
下面我要简单解释一下这些传递方式:
//1
char c[][4]={"aaa","bbb","ccc"};
void doit(char **c) {
//c[0][0]='z'; 不合法
for (int i=0;i<2;i++)
cout<<c[i]<<endl;
return;
}
方法一的传递方式,是完全不能支持修改的
//2
char c[][4]={"aaa","bbb","ccc"};
void doit(char *c[]) {
//c[0][0]='z'; 不合法
...
}
很遗憾,方法二的传递方式,也不能支持修改
//3
char *c[4]={"aaa","bbb","ccc","ddd"}; //注意这里的定义形式
void doit(char *c[4]) {
//c[0][0]='z'; 不合法
...
}
想要使用方法三提出的传递方式,在定义的时候就需要保持一致
不支持修改 /我裂裂裂裂裂开
//4
char c[][4]={"aaa","bbb","ccc"};
void doit(char c[][4]) {
for (int i=0;i<3;i++)
cout<<c[i]<<endl;
c[0][0]='z';
cout<<c[0]<<endl;
return;
}
输出:
aaa
bbb
ccc
zaa
支持修改的好榜样
//5
char c[2][4]={"aaa","bbb"};
void doit(char c[2][4]) {
for (int i=0;i<2;i++)
cout<<c[i]<<endl;
c[0][0]='z';
cout<<c[0]<<endl;
return;
}
输出:
aaa
bbb
zaa
定义数组的时候需要确定大小,同样支持修改
写在最后:
可能是有点着急了,所以代码给的都不是很完整,这对于基础薄弱的宝贝们可能非常不友好
某位憨憨反映看不太懂(/撅嘴),所以我就添加了一些代码细节和注释,希望可以帮到大家吧~
欢迎大家提出建议咯~~