很多刚从C转C++的人都不明白,在C中这样的代码
char *pChar="hELLO!"; //定义字符指针pChar,指向一个字符数组首元素即h
*pChar='H'; //问题所在行
到了C++中怎么就不行了?你翻遍参考书,都会说,pChar指向的是常量,怎么能允许改变呢?你又问了,怎么我在C中运行的好好的?没人回答你。于是,你只好自我安慰,这就是C++的保护机制吧。
我来做个总结吧,发现这个问题如果不深入研究一下,总是人云亦云,就像我以前那样。于是,我用BC++3.1编译这段代码后运行,无论是编DOS程序还是Windows程序都是能运行的,结果也和你预期的一样。没什么问题。但是VC++6运行时就会出错,错误你想必相当熟悉(XX内存不能写)。但这只是编译器的问题的吗?
你可以把你在VC++中编译的程序拿到纯DOS下运行,哪怕他是Console程序,他也会说“Can not run in DOS”,因为他是32位的。而BC++3.1哪怕是编一个Windows程序,也只是16位的。所以问题的关键在于内存的管理上。32位系统对于应用程序使用的内存定义了操作权限,能读还是能写,或者是其他什么。而16位的系统缺乏这种安全机制,哪怕你说这段数据只能读,但是写一下也没什么关系。
这种代码之所以能在C中运行的很好,就是因为那时C的编译器都是16位的;现在在C++中不行了,是因为你用的C++编译器是32位的——能找到BC++3.1这种古董还真不容易,相对而言TC2.0更好找。我反汇编TC2.0生成的这两条语句char *p = “hellow”;char p[] = “hellow”;发现他们的实现并不相同,相对而言,char *p = “hellow”;生成的代码更简洁一些。虽然C也想定义常量字符串,但由于16位的欠缺保护,这种想法被人误解了;几乎所有学习过C的人都曾耗费力气去理解如上的代码,然后泛滥的使用。不为别的,只因为这种代码效率高,从反汇编结果能看出来。于是使用char p[] = “hellow”;这种语法的人被嘲笑,但事实上,这种语法才是本意,那种语法只是钻了个空子,于是,在32位程序中,他被剥夺了生存的权利。
这让我想起了C中很多怪异的写法,虽然他们让人很费解,但是确实,他们的效率要比容易看懂的写法来得高,当然,我不知道这其中有没有钻空子的例子;从C设计的本意来说,他们有存在的意义,但是从现在的程序设计潮流来看,代码的可读性要求超过了他的效率。不知道这些语法能不能算是程序员中的一种外语——想写高效的程序吗,掌握我吧,哪怕是死记硬背。
PS:32位系统运行16位程序采用的是模拟仿真的方法,就是说和运行在16位系统一样。
C语言没有专门定义字符串数据类型(如其他语言中的string),它用以'\0'结尾的字符数组来表示一个逻辑意义上的字符串。
字符数组主要有两种用途,(1)存储字符串,(2)存储字符或字符变量。这两个是不同的,刚开始接触时很容易混淆。下面进一步分析这两者的不同。
首先初始化时不同,用于存储字符串,例如:char str[]="Hello"; 用于存储字符或字符变量,例如:char Chars[]={`H``e`,`1``1`,`o`}。这两者的存储方式是一样的,但是存储内容稍微有所不同,那就是第一种情况会在结尾加上‘\0’,存储情况类似于{`H``e`,`1``1`,`o`,`\0`},存储空间会比第二种情况大一点,但是这个存在空间并不被计算进字符串(其实只是字符数组)变量中。
C语言中提供的字符串操作函数其实是针对于结尾是`\0`的字符数组进行的。输出函数printf中的输出参数%s也是针对于结尾是`\0`的字符数组。
另外,还有一种方法可以定义字符串(其实也是字符数组),申明如下:
char * string = "this is a point charArray.";字符指针指向字符数据的第一个字符的位置。
最后,有两点特别说明。
(1)字符串常量给出的是地址值。如
char *p, s[10];
p="hello";//正确
(2)不能用赋值语句给字符数组整体赋一串字符,例:
char str[10];
str = "abc"; //错误
正解的赋值办法是给数组元素逐个赋字符值,最后人为加'\0'。
--------------------------------------------------------
C语言里定义一个字符串可以使用指针也可以使用数组,如:
(1) char *s="hello"; //"hello"是字符串常量,s是指向常量的指针,常量是不允许改变的,不能写成s[0]=X,但可以改变指针的值,使其指向不同的常量,如 s = "Xeron";
(2) char s[]="hello"; //指针常量,s本身的值不能修改,但可以修改其指向的内容,s[0]=X
两者的区别是
(1)定义的字符串在程序里不能被修改,因为它存放在代码段内;
(2)定义的字符串可被修改,它存放在数据段或者栈内。
这两种定义字符串的方法在函数内部和外部稍有区别
*函数外部:
(1) char *s="hello"; /*定义了指针s(数据段)和常量字符串"hello"(数据段),s的值为字符串首地址*/
(2) char s[]="hello"; /*定义了字符数组s,数组内容为"hello"(代码段),注意这里s只是一个符号而不是变量实体*/
*函数内部:
如果在函数内部使用(1),(2)定义,则"hello"字符串本身存放在代码段,当函数被调用时,
(1) 仅把字符串"hello"的首地址地址赋给s
(2) 把字符串"hello"拷贝一份放到栈内,把拷贝串的首地址赋给s
所以(1)中s所指的内容不能改变,而(2)中s所指的串可修改,s指向的是"hello"串的拷贝,不会影响原串,每次调用函数的时候都拷贝一次
注:在函数内部使用(1)(2)是没有加static关键字修饰的,如果加了static关键字,那就跟在函数外部没什么区别了.
******************************
(1)稍加改变就能满足"hello"串可修改
char *s = (char []){"hello"}; //好像不可行
此时匿名"hello"串存放在数据段。
也可以给定义一个匿名数组赋给int型指针,如:
int *p=(int [10]){[0 ... 9]=0};
----------------------------------------------------------------------------------------
malloc()和free()的基本概念以及基本用法:
1、函数原型及说明:
void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针。如果分配失败,则返回一
个空指针(NULL)。
关于分配失败的原因,应该有多种,比如说空间不足就是一种。
void free(void *FirstByte): 该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,
让它重新得到自由。
2、函数的用法:
其实这两个函数用起来倒不是很难,也就是malloc()之后觉得用够了就甩了它把它给free()了,举个简单例子:
程序代码:
// Code...
char *Ptr = NULL;
Ptr = (char *)malloc(100 * sizeof(char));
if (NULL == Ptr)
{
exit (1);
}
gets(Ptr);
// code...
free(Ptr);
Ptr = NULL;
// code..