搜尋

首頁  >  問答  >  主體

字符串 - C++中字符常量有什么用?

刚学C++,看书上说几种常量,数值常量我能理解,PI是个好例子。但是字符常量又要作何解?转义字符这个倒还好理解,有个实际用处单独定义出来。但是还有普通的字符常量,这个我就非常理解不能了,请问大家能不能给个例子证明这个有什么用?而且只能单引号什么的其实也挺纠结的。
另外,C++是不是强语言,每个变量都必须定义类型什么的?没办法,从PHP转过去的,挺纠结这些基本问题的╮(╯▽╰)╭...
再来就是定义字符串常量查到好几种方法:

#include<string>
string url = "segmentfault.com";
const char url[] = "segmentfault.com";
const char *url = "segmentfault.com";
const char* url = "segmentfault.com";

请问哪个好点?另外最后两个的*号做何解...新手问题还望大家要淡定,别凌乱就好。。。。

伊谢尔伦伊谢尔伦2808 天前740

全部回覆(3)我來回復

  • 大家讲道理

    大家讲道理2017-04-17 11:04:23

    先說說這幾個例子的區別吧:
    1、

    #include<string>
    string url = “segmentfault.com”;

    url是一個string對象。為了更加容易地操縱字符串,cpp為我們定義了一個string類(string並不是cpp的關鍵字),你可以通過它來定義字符串對象,然後通過調用它的方法來獲取該字符串的信息,例如獲取它的長度:
    url.length()
    又或者對它進行操縱,例如拚接:

    string scheme = “http://”
    cout << scheme+url << endl; //输出http://segmentfault

    2、
    下麵的三種寫法都可以看作是一種:

    const char* url = “segmentfault”;

    因為 const char url[](字符數組),數組名url在編譯時會被隱式轉為為指針char*,指向字符串的首個字符's'。至於*號的位置,有人喜歡把它放到靠近類型,有人喜歡把它放到靠近變量名,這裏有一個關於這個問題討論的topic

    http://topic.csdn.net/u/20101117/10/f...

    又因為是常量字符串,所以你不能對它進行修改

    url[0]='x';//错误,不可以进行修改,就算没有用const来修饰,也不可以

    但是在string中卻可以

    string url = “segmentfault.com”;
    url[0] = 'x';//OK

    這是因為string為我們承擔了管理內存的任務。如果你想要對它進行拚接,你需要自己寫一個函數,又或者調用cstring庫中的strcat或strncat函數。

    在c/cpp中,*有兩種作用,一種是用來定義指針類型,char* 就是字符指針。另外一種就是取值,取指針指向的值,想上麵所說的

    const char *url = “segmentfault”;

    url是指向字符串的首個字符,所以你對指針url取值,得到的就是字符's'

    cout << *url << endl;//输出's'

    所以,總的來說,string用起來會比較方便,常量字符串在操縱起來就有點麻煩,也可以說是靈活吧,什麼時候用哪個,就需要你自己衡量了。至於性能上,我想我還沒有能力來分析!

    回覆
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 11:04:23

    補充一下 @Henry 的答案
    字符串數組和指針,雖然兩個很相似,數組可以在使用時退化成指針使用,但是兩個概念上就不一樣。
    關鍵的一點在於,指針存放的是一個地址
    舉個例子:

    const char str[] = "segmentfault.com";
    const char *str_ptr = "segmentfault.com";
    
    // sizeof(str) == 17
    // sizeof(str_ptr), 平台相关, x86的目标文件一般为4(32位), x86_64的目标文件一般为
    //   8(4位)

    EDIT:

    利用這點可以在編譯時就確定出字符串的長度。

    理解了指針是地址之後,下麵的錯誤就不會犯了:

    define.c

    // 定义该字符串常量
    const char str[] = "segmentfault.com";

    main.c:

    // 错误的声明
    extern const char *str;
    // 正确的声明
    //extern const char str[];
    
    int main()
    {
        // 产生段错误
        // 原因: str本来是数组,但是声明为了指针
        //   假设目标文件是32位 x86 小端格式
        //   则实际访问的错误地址是 0x6d676573 (刚好就是segm这4个字符的ASCII码)
        printf("%s\n", str);
        return 0;
    }

    回覆
    0
  • 高洛峰

    高洛峰2017-04-17 11:04:23

    由於曆史原因,c 兼容c的字符串。c風格字符串使用char[]或者const char *來表示。字符串字麵值也被編譯器推導為const char *

    windows環境下,字符串編譯後被存在.rsrc區段中(區段是可以隨意改名的,不同編譯器實現也可能不同,可以打開peid去查)。這個區段是隻讀的,你如果強行寫入程序會崩潰,所以為了保險起見給你const char *

    但是現代的c 編程不提倡用c風格字符串(就像obj-c也不提倡使用c風格字符串,而是NSString),所以你隻要記住上麵那一點,並且使用std::string就好了。遇到c風格字符串,如果你要使用,應該馬上用string的構造函數轉換為string

    記住,你寫的是c ,不是c!

    構造函數調用有兩種形式,一種是函數形式,比如string url("segmentfault.com")。但是,特別地,如果構造函數隻有一個參數,可以寫成賦值形式,即:

    #include<string>
    string url = "segmentfault.com";

    隻要這是對象的初始化,而且存在相應的構造函數,就會編譯成構造函數的調用。而不是先創建string,再調用operator =。上麵那句話的實際作用是拿const char *來構造string

    或者如果你想讓編譯器推斷為string類型,在它後麵加個s。

    auto url = "segmentfault.com"s;

    你如果用char []保存字符串,那它是存在棧上的。

    是因為原生數組的名字,可以被編譯器推導為低一級的指針,指向數組起始位置,比如char[]在使用時會被當作char *

    char[]和別的數組不同的地方還在於可以用字符串字麵值初始化。

    如果你這樣寫:

    char str[] = "segmentfault.com";

    就相當於

    char str[] = {'s','e','g','m','e','n','t','f','a','u','l','t','.','c','o','m','rrreee'};

    回覆
    0
  • 取消回覆