zoukankan      html  css  js  c++  java
  • 字符串指针与字符数组(ZT)

    很多刚从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..

  • 相关阅读:
    Eclipse Java开发环境配置 + memcached + maven
    sqlserver数据库自动备份
    从表A中选择部分字段插入到表B
    电信IOT平台关于产品profile插件的添加流程
    SQLServer查询耗时sql语句
    net core 包管理
    byte[] 截串操作
    关于kafka启动失败问题
    springboot 搭建maven项目
    C# MongoDB学习之路(一)
  • 原文地址:https://www.cnblogs.com/danghuijian/p/4400872.html
Copyright © 2011-2022 走看看