`
weiyinchao88
  • 浏览: 1234567 次
文章分类
社区版块
存档分类
最新评论

从语句 char* p="test" 说起

 
阅读更多
从语句 char* p="test" 说起
我相信,使用C/C++多年的人对下面这个字符串赋值语句都不会陌生吧。
char* p = "test";
同时,我也相信,各位在使用这种语句后吃过很多苦头也不少吧?只要你想利用指针p来改变字符串的内容,你的程序都会得到一个让你颜面尽失一个内存非法操作。比如,下面的这些语句:
p[0] = 's';
strcpy(p, "haoel");
原因就在于,char* p = "test"; 这个声明,声明了一个指针,而这个指针指向的是全局的const内存区const内存区当然不会让你想改就改的。所以,如果你一定要写这块内存的话,那就是一个非常严重的内存错误。另,之所以加粗“全局const内存区”,是强调一下,如果你不信的话,你可以试试下面这段代码,看看p1p2的地址是不是一样的。
char* p1 = "anything";
char* p2 = "anything";
printf(“ p1=%x, p2=%x /n”, p1, p2);
我想这应该是一个众所周知的问题吧。取而代之的,应该是使用数组来做初始化声明。如:char str[] = “hello world”; 如果现在还有哪本书中的C的示例采用了使用const字符串初始化指针的这种方式,那么你就可以把那本书撕了,如果这本书是C++的书话,那么你应该把这个作者和这个出版社告上法庭,因为你不应该容忍这种学术骗子。如果你的部门的开发人员还有人写出这种代码的话,如果他是C程序员,我想你可以在打过他的屁股后告诉他下不为例,如果他是一个C++程序员的话,我想你可以怀疑他是否有资格做一个C++程序员了。
至于你问我为什么要对学C++的人那么苛刻,那是因为学过C++的人都知道C++中的const关键字的有着什么样的权力,你也应该知道C++const有着无比的照顾和关爱,几乎所有关于C++的书都会提到const这东西。所以,如果作为一个C++的程序员来说,如果你不知道的话,那就太说不过去了。
我们知道,双引号引起来的字符串是const的,所以,在C++的世界中,你应该进行如下的声明才比较稳妥:
const char *p = "test";
这样,当你修改这个字符串的内容时,编译器会给你一个错误而导致你的程序编译不通过,从而不会产生运行时的内存错误。
可问题是,像C++这种对类型要求很严格的语言来说,为什么它在编译诸如char *p="test" 程序的时候不出错,甚至连个警告都没有(g++vc++7)?难道这是他的一个bug?我想,这应该是对古老的C的一个向下兼容。因为,在C的世界中,这种用法太多了。
C++中,比如:函数的参数和异常的捕获都存在这种问题,如下所示:(因编译器而定,在gcc 3.4.3版中,下例中的异常示例不能被捕获,但VC++6中却可以被捕获)
func( char* p) { } // 以这种方式调用函数func(“abc”);
try { thow “exception”; } catch (char* p) { }
这些都是C++编译器默认了可以把const char* 转成 char* 的罪行,无疑会对大家是一个误导。甚至让人无所畏惧地走入其中,并自以为走入了正途。这样看来,这种向下兼容的C++标准,就显得有点误人不浅了
不过好在,C++标准委员会早已意识到了这一点。这个C++feature被定义为了“Deprecated Feature”,即“不被建议使用的特性”。意思就是,在将来,这种特性将被从C++中移出,于是,你目前的这种程序将无法在新的C++编译器上编译通过。对于程序的可移植性来说,我们今天所写的代码尤其要注意这些“Deprecated Feature”。
据我所知,目前C++中被列为“Deprecated Feature”如下所示(可能不准确,请大家指正)下面的这些feature都已被C++标准委员会订为废除featrue了。
一、 隐晦的字符串的const转换。

char *p = "test";
w_char *pw = L"test";

把一个const的字符串类型转成non-const的。包括指针和数组。
二、 隐晦的类型声明。

func() {} //函数的隐晦返回类型是int
static num; //变量的隐晦类型是int
这种featureC89中还可以使用,但在C99C++中都被去除了。(gcc 3.4版本对于这种声明会给出编译错误,而VC++6.0会认为这是合法的程序)
三、 布尔变量的累加操作。
bool isConn = false;
isConn++; //这个操作会把isConn变为true
就目前而言,几乎所有的编译器都认可这种操作,但这种用法也是不被建议的,终有一天会被取消。
四、 更改父类成员的存取权限。
class B
{
protected:
int i;
};
class D : public B
{
public:
B::i; //这种方式可能大家很少看到。
};
对于这种语法,子类重新暴露了父类的私有成员。这会带来很大的安全性问题。目前而言,这个feature对于所有的编译器来说应该都是可以编译通过的(连个Warning都没有)。但这个feature也是要被废除的。
五、 文件中域的static声明
static int i;
static void func()
据说,这种旧的在C中的为了实现其作用域在本文件中的feature在未来的C++中也要被取消。
文章到这里应该结束了,在结束之前,让我再给大家共享一个有趣的关于const的例子(在网上看到的)
const int a = 1;
int *p = const_cast<int*>(&a);
*p = 2;
cout << “value a=”<< a << endl;
cout << “value *p=” <<*p << endl;
cout << “address a=” <<&a << endl;
cout << “address p=” <<p << endl;
这段代码输出的结果如下:
value a=1
value *p=2
address a=0xbff1d48c
address p=0xbff1d48c
地址都是一样的,可值为什么不一样呢?呵呵。这个问题看起来有点“学术味”过浓,不过是个好例子,可以让你知道C++的一些用法和一些原理。有以下几个方面大家可以考虑一下:
1)const int a = 1是不是和宏有点像,会不会被编译器优化了?
2)去修改一个const的值,本来应该是不对的。这可能会是向旧的C兼容。是否会让编译器产生未知行为?
所以,这个示例也告诉我们,我们应该遵循C++中的constnon-const的语义,任何想要破坏这个语义的事情都会给我们带来未知的结果。
分享到:
评论

相关推荐

    C语言指针用法详解

    - **指针类型**:从语法角度来看,去掉指针声明语句中的指针名称后剩余的部分就是指针的类型。 - `int *ptr;`:指针类型为`int *`。 - `char *ptr;`:指针类型为`char *`。 - `int **ptr;`:指针类型为`int **`...

    华为笔试题大全(史上最齐全)

    14. **switch参数类型**:switch语句的参数不能是浮点型。 最后,两个编程题: - **数组重新排列**:要求不使用额外空间且保持有序,可以使用双指针法,一个从头向尾扫描,一个从尾向头扫描,当找到0时,与非0元素...

    练习题选择题答案.docx

    `,正确的赋值语句是 `p=&n ;`。在第4题中,正确的赋值语句有 `p1=&m; p2=&n; *p1=*p2 ;` 和 `p1=&m; p2=p1 ;`。 三、字符串操作 字符串操作是指针操作的重要应用之一。在第6题中,字符串 `char *a=”china”;` ...

    关于char (*p)[] 和char p[]的问题

    因此,我们不能将数组名当作一个指针来使用,例如 `p=a` 就是一个错误的赋值语句。我们应该将数组名当作一个指针来使用,例如 `p=&a`。 指针数组、数组和指向数组的指针是三个不同的概念,我们需要区分它们之间的...

    C++指针函数习题.doc

    那么能通过scanf语句正确给输入项读入数据的程序段是*p=&a; scanf(“%lf”,p);。 5. 指针变量的地址表示 设有语句int *point,a=4;和point=&a;下面均代表地址的一组选项是&a,*&a,*point。 6. 字符串占用字节数 设...

    C#使用非托管代码直接修改字符串的方法

    代码如下:using System; public class Test{ public static void Main(string[] args) { string str = “hello”; ToUpper(str);...p++) { *p = char.ToUpper(*p); } }}fixed语句:格式 fix

    C++试题参考答案

    void test3(char* str1) { char string[10]; if (strlen(str1) &lt;= 10) { strcpy(string, str1); } } ``` - **错误分析**:`strlen(str1)` 返回字符串的长度,不包括末尾的 `\0` 字符。因此,如果 `strlen(str1...

    华为软件工程师经典笔试试题

    2. void setmemory(char p, int num) { *p=(char *) malloc(num);} void test(void) { char *str=NULL; getmemory(&str,100); strcpy(str,"hello"); printf(str); } 运行 test 函数将输出“hello”,因为strcpy(str,...

    C++程序员应聘常见面试题及试题深入剖析

    char* p = (char*)malloc(100); return p; } ``` #### 字符串处理详解 **关于 `strcpy` 的实现:** - **2分版本:** ```cpp void strcpy(char* strDest, const char* strSrc) { while ((*strDest++ = *...

    C语言中char*和char[]用法区别分析

    本文实例分析了C语言中char* 和 char []的区别。分享给大家供大家参考之用。具体分析如下: 一般来说,很多人会觉得这两个定义效果一样,其实差别很大。以下是个人的一些看法,有不正确的地方望指正。 本质上来说,...

    C语言指针练习+答案+讲解.doc

    "C语言指针练习+答案+讲解" 本文档提供了C语言指针的练习题和答案说明,涵盖了指针定义、指针赋值、指针运算、scanf函数的使用等多个方面。...p是指向双精度浮点数变量x的指针,正确的赋值语句是p=&x。

    程序员面试宝典题目总结

    int test(char var[]){ return sizeof(var); } ``` **知识点解析:** `sizeof(var)` 在函数内部返回的是指针的大小,而非数组的大小。这是因为传递给函数的是数组的指针,而不是整个数组。 **答案:** 返回值为 `...

    2020尚硅谷 谷粒商城 建表sql语句

    /*==============================================================*/ /* Table: pms_attr */ /*==============================================================*/ create table pms_attr ( attr_id bigint not ...

    华为软件笔试

    2. void setmemory(char p, int num) { *p=(char *) malloc(num);} void test(void) { char *str=NULL; getmemory(&str,100); strcpy(str,"hello"); printf(str); } 运行 test 函数将输出 "hello",因为 getmemory ...

    华为(嵌入式)笔试题

    char * const p; //常量指针,p的值不可以修改 char const * p; //指向常量的指针,指向的常量值不可以改 const char *p; //和char const *p 这三个声明的指针的区别在于,第一个是常量指针,p的值不可以修改;第二...

    华为C语言面试题集 C语言面试题-华为C语言面试题 深圳华为面试

    char*dest = (char*)malloc(len + 1); // 额外分配一位存放字符串结束标志'\0' char*d = dest; char*s = &src[len - 1]; // 初始化指向源字符串的最后一个字符 while(len-- != 0) { *d++ = *s--; // 正确地使用...

    深入分析C++中char 和char []的区别.docx

    "深入分析C++中char和char []的区别" 本文将深入分析C++中char和char []的区别,探讨其在内存中的存储方式和使用场景。 首先, lets 看看下面的代码: ```c char *c1 = "abc"; char c2[] = "abc"; char *c3 = ...

    C语言考试题答案 仅供参考

    因此,我们可以通过四个if语句比较四个整数并交换位置,最终实现从大到小的排序。 4. 题目要求计算阶乘序列的和,使用递归函数实现: 这里定义了一个递归函数`fun`,当N等于1时,返回1/(N+1),否则返回1/(N+1)加上...

    浅析char 指针变量char *=p 这个语句的输出问题

    学习指针的时候我一直有个疑惑,请看下面的代码: #include using std::cout; void main() { int num=5; int *nPtr=# cout&lt; using std::cout; void ma

    C语言删除特字符串

    char *p = string; int b = '1'; // 这里的'b'赋值为'1'似乎没有实际用途 for (; *p != 0; p++) if (*p == a) *p = b; // 如果遇到匹配的字符,则用'b'替换 p = string; puts("thesequenceis\n"); for (; *p...

Global site tag (gtag.js) - Google Analytics