关于字符串的分析
注:编译环境vc6.0
一、char str[20]; 字符数组
1、声明(也可以说定义,因为程序下文中用到了str,声明便为定义)
执行以下代码:
#include "stdio.h"
void main(){
char str[20];
for(int i=0;i<20;i++){
printf("%c %d",str[i],str[i]);
}
}
输出的结果为:
由此可见:
c语言如何创建字符串数组仅仅声明char str[20]; 名为str的字符数组中的每一个元素有初始值吗?由ASCII码知,-52(十进制)不是任何一个标准字符,难道仅仅声明长度固定的字符数组会将它的所有元素初始化为这个十进制为-52的字符吗?
执行以下程序,似乎更加说明了这个问题:
#include "stdio.h"
void main(){
char str[20];
for(int i=0;i<20;i++){
printf("%c %d",str[i],str[i]);
}
}
输出的结果为:
观察得到,第20个字符之后的字符就开始不一样了。而前20个完全一样,刚好是申请的字符个数。这说明了什么呢?
我的猜测:
声明str[20],那么这20个单元从可利用空间表(A V ALL表)中分配而来,组成一个数据结构为char 并且大小为20的占用块(活动记录表),可能在这种环境下,A VALL表中的每一个字节的数据都是-52。而多余的单元(仅仅申请了20个单元),当i>=20 的时候,输出语句printf("%c %d",str[i],str[i]);访问的数据位于什么位置,至少不在这个占用块中。所以之后的字符会不同!
根据上面继续猜测:
既然在占用块中的元素未赋值之前为同一个值,那么无论什么类型的元素,当获得一个占用块时,每个单元中(当然,单元所占字节应该一样)的数据应该完全一样,即与类型无关。
执行以下程序,似乎更加说明了这个问题:
#include "stdio.h"
struct node{
char a;
char b;
char c;
char d;
};
void main(){
node n1;
printf("%d\n",sizeof(n1));
int a[20];
for(i=0;i<20;i++){
printf("%d ",a[i]);
}
printf("\n**************************************************************************\n");
node n2[20];
for(i=0;i<20;i++){
printf("%d ",n2[i]);
}
}
执行结果为:
这不用多作说明了。需要弄明白的就是-52(十进制)或者说'?' 到底是个什么?可用空间内存单元的缺省值。
2、初始化
关于初始化的严格定义?——在定义变量的时候给变量赋初值。
初始化一定是给变量赋初值,但给变量赋初值一定就叫做“初始化”吗?显然不是。这里只分析初始化。如下语句:
char str[20]="hello world.";
执行以下程序:
#include "stdio.h"
void main(){
char str[20]="hello world.";
for(int i=0;i<20;i++){
printf("%c%d ",str[i],str[i]);
}
}
输出结果为:
可见初始化字符数组之后,数组中未被赋值的地方将自动写为字符结束符(' \x0 ')。
3、赋值
char str[20]中,str'是数组名,也是一个指针,是一个指向char类型的const指针,即:
A、指针的值不允许改变
B、可以通过指针改变指针所指变量的值
关于指向char类型的const指针,必须初始化,并且初始化有4种形式:
①char* const p="hello world";
p所在的内存区域先不讨论,一般变量如果是全局变量则在静态存储区(全局区),如果是局部变量则在栈区,但是p是一个const变量,所以先不讨论。但是hello world\0则一定在常量区,所以无法通过p的值去修改p所指字符串的值(编译会通过,但运行会出错)。
②char* p1="hello world"; char* const p=p1;
同上,因为hello world\0在常量区,所以不能通过p的值去修改p所指字符串的值。
③char str[20]="hello world"; char* const p=str;
此时hello world\0在常量区,但是str[20]却在全局区(或者栈区)。就是说:char str[20]="hello world";语句创建了两份hello world\0,一份在常量区,一份在全局区(或者栈区),并且数组名(实际上是一个不可以修改值的指针)中保存的是栈区那连续的20个单元的首地址。
所以,这种情况可以通过p去修改p所指内容的值。
④char* p1=new char[20]; char* const p=p1;
这时应该分2种情况说明:
第一种:
char* p1=new char[20];
p1="hello world";
char* const p=p1;
显然这种情况依然不能通过p去修改p所指字符串的值。为什么,就不用多说了。
第二种:
char* p1=(char*)malloc(5);
int i=0;
while(i<4){
scanf("%c",&p5[i]);
i++;
}
p5[i]='\0';
char* const p=p1;
*p1='H'; //(等价语句*(&p6[0])='E'; )
printf("%s\n",p6);
以上代码能正确运行,与上面的情况比较可得到理所当然的结论:
p1位于全局区(或者栈区),但是p1指向堆区的5个单元,p指向p1,p的值不可改变,但可以通过p去改变p所指内存中的值。而上一种情况,虽然开始时p1指向堆区中的内存,可是紧接着就让p1指向了常量区,所以不能通过p去改变p所指内存中的值。
以上说了这么多,重新回到字符数组的赋值操作上面:
显然字符数组的赋值只能一个一个的往数组单元中写,可以用for语句,也可以用while等。。。。但是当我们写完最后一个数的时候,C/C++标准规定了自动在字符串末尾添加\0(字符串结束符)吗?
比如我们声明了一个长度为n的字符数组str,则我们最多只能往里面写n-1个字符(即只能写到str[n-2]),最后一个单元用来保存'\0'。现在的问题是:这个\0 是我们手动添加还是系统自动添加?
答案很明显:需要我们(程序员)手动添加。
二、#define SIZE20
char* str=(char*)malloc(SIZE); ------------------C语言动态分配的字符串(char* 字符串)
上面的SIZE可以是一个int变量!
以下是其C++的等价版:
int n=10;
char* str=new char*[n]; -----------------------------C++ 动态分配的字符串
这个没有什么好说的,上面两种方式基本一样。
①若str是全局变量,则str位于全局区,开辟的空间位于堆区。
②若str是局部变量,则str位于栈区,开辟的空间位于堆区。
补充一点:末尾字符结束符'\0' 需要自己(程序员)自己添加。
但是有一点需要十分注意:
*若是在上面的语句下面紧接着有一条语句: str="hello world"; 那么str虽然依然在原来内存区域,但是str指向的地方改变了,由原来的堆区变为了常量区。所以这种情况要十分注意:其实这造成了内存泄漏!!!
三、string str; ----------------C++字符串
这是一个C++类,在C++ Primer上面有比较详细的说明。挑拣一些自己的看法:
1、构造函数
①普通构造函数
string(const char* str="");
这个构造函数有个十分需要注意的地方,此处不再说明。
②复制构造函数
string(const string str);
③转换构造函数!!??
C++的STL中对于string 没有转向char*的类型转换函数,但是c_str()函数具有该作用。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。