关于字符数组和字符串指针的困惑

    字符数组和字符指针可谓是我学C语言时最让人迷惑的了,下面让我娓娓道来!

int main()
{
	char * ter = "terrific";    //这是一个赋予ter地址的过程
	char * exc = "excellent";
    printf("%p\n", ter);   //将打印出"terrific"的内存地址
    printf("%p\n", exc);    //将打印出"excellent"的内存地址
    return 0; 
}
     字符指针变量ter和exc被分别赋值为"terrific"和"excellent"变量的内存地址,让ter和exc有了归宿,指向了具体的内存区域。理解了这一点,就可以继续往下看了。

int main()
{
	char * poem = "Rain is falling all around";
	printf("%p\n", poem);  //静态存储区地址
	char str[] = "It falls on field and tree";
	printf("%p\n", str);       //栈中的地址
	printf("%p\n\n", &str[0]);
	
	str[3] = 's';    //合法语句
	//poem[3] = 's';  此语句非法
	
	printf("%c\n", *(++poem));
	//printf("%c\n", *(++str));  str不能被改变,语句非法 
	printf("%c\n", *(str+3));
	
	poem = str;     //str是常量,将常量赋值给一个指针变量poem合法
	/*
	str = poem;
	char ctr[30]; 
 	ctr = "two birds with one stone";   //这些都是错误的,数组常量是不能作为左值的
    */	
	return 0;
}
上面的程序显示结果是:


    poem这种字符指针指向的字符串位于静态存储区,该内存块为只读,另外poem是指针类型,poem的值可以被改变。
    str是在栈上分配的内存,main函数结束后会自动释放,str不是一个指针类型,充其量可以称他是数组类型,str是一个常量,保存着数组中第一个字符的地址,可以把它当做一个指针来用,但是不能改变其值。(从结果显示图中,可以发现栈和静态存储区分配地址的方式是不一样的)
    综上所述,对于poem[3] = 's';这条语句的非法,就可以解释为:字符数组保存的字符串存放在内存的栈中,而字符指针指向的字符串保存在内存的静态存储区中,这一块内存是只读内存区域。所以字符数组保存的字符串属于字符串变量,可以被修改,而字符指针指向的字符串是属于字符串常量,不能被修改,这个类似数组名是常量不能被修改一样。

     

    Next, 来看看字符指针指向一个堆中动态内存的情况:

int main()
{ 
    char * tai = (char*)malloc(sizeof(char)*50);
    printf("%p\n", tai);      //tai在堆中内存首地址
    tai = "when day is done";
    printf("%p\n", tai);         //tai在静态存储区内存首地址
    char * taige = "if birds sing no more";
    printf("%p\n", taige);     //tai在静态存储区内存首地址
    return 0;
}
  运行结果:

 

    tai指针是存储在栈中的,但它的内容是malloc后的堆内存的地址。由于tai指向的地址内容是用malloc在堆上分配的,它的生命周期是动态的,要由程序员手动用free来释放。
如果没有释放,则会在程序结束才被释放,也就是在free之前,该空间一直存在。

    发现没有,tai指针变量被赋一个字符串后,地址却变了,说明tai被重新赋值了,指向了静态存储区的地址。那将这个保存字符串地址的变量tai设为const呢?const的意思就是让tai本身的值不能被改变。看下一段代码:

int main()
{
    char * const tai = (char*)malloc(sizeof(char)*50);
	if (tai == NULL)
	{
		printf("内存分配出错!");
		exit();
	}
    printf("%p\n", tai);      //tai在堆中内存首地址
    //tai = "when day is done";  编译出错,tai是一个只读变量,只能是堆中的那个地址,不能重新给tai一个静态存储区的一个地址
    tai[0] = 't';
	*(tai+1) = 'h';
	tai[2] = 'e';
	*(tai+3) = 'b';
	*(tai+4) = '\0';   /*给字符串一个结束的标志因为malloc在动态分配完内存后,
	                     不会初始化内存,里边数据是随机的垃圾数据。*/
	printf("%s\n", tai);
	printf("%p\n", tai); 
	
	free(tai);   //为了防止垃圾数据,亲们最好记得malloc之后free一下
	
	return 0;
}
运行结果:


可以往堆中分配的内存写入数据了,大伙是不是有点激动!上面的程序也是动态分配内存的字符数组进行初始化的一种方式。

再来对比一个字符数组的例子:

int main()
{
    char tai[20];
    tai[0] = 't';
	*(tai+1) = 'h';
	tai[2] = 'e';
	*(tai+3) = 'b';
	//tai[4] = '\0';     没有加上手动附上'\0'时,会把垃圾数据给输出来
	printf("%s\n", tai);
	printf("%p\n", tai); 
}
看结果:

在定义字符数组时,我们可以进行初始化,防止出现注意不到的错误,如:char tai[20] = {'\0'}。

更多知识请看:
http://www.cnblogs.com/GODYCA/archive/2013/01/31/2888331.html
http://c.biancheng.net/cpp/html/2752.html




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值