c/c++字符串定義及使用的對比


gcc支持的一種的字符串的表示形式 "xxx" "xxx" "xxx" 他會將這3個字符串連成一個並
且只會在最后的一個字符串末尾添加 '\0‘,而且還會忽略各個字符串之間的空格符號。

當我在由GCC編譯的Linux x86_64計算機上編譯並運行以下C程序時:

include <stdio.h>

int main(void)
{
char *p1 = "hello"; // Pointers to strings
char *p2 = "hello"; // Pointers to strings
if (p1 == p2) { // They are equal
printf("equal %p %p\n", p1, p2); // equal 0x40064c 0x40064c
// This is always the output on my machine
}
else {
printf("NotEqual %p %p\n", p1, p2);
}
}

我總是得到的輸出為:

等於0x40064c 0x40064c

我知道字符串存儲在常量表中,但是與動態分配的內存相比,地址太低了。

與以下程序比較:

include <stdio.h>

int main(void)
{
char p1[] = "hello"; // char arrar
char p2[] = "hello"; // char array
if (p1 == p2) {
printf("equal %p %p\n", p1, p2);
}
else { // Never equal
printf("NotEqual %p %p\n", p1, p2); // NotEqual 0x7fff4b25f720 0x7fff4b25f710
// Different pointers every time
// Pointer values too large
}
}

兩個指針不相等,因為這是兩個可以獨立操作的數組。

我想知道GCC如何為這兩個程序生成代碼,以及它們在執行過程中如何映射到內存。由於已經將其記錄在文檔中,因此很多時候都歡迎使用任何指向文檔的鏈接。

在C中定義字符串有下列幾種形式:字符串常量,char數組,char指針

1.字符串常量

即:位於一對雙括號中的任何字符。雙引號里的字符加上編譯器自動提供的結束標志\0字符,作為

一個字符串存儲在內存中。如:printf("%s","hello"); //"hello"

如果字符串文字中間沒有間隔或間隔的是空格符,ANSI  C 會將其串聯起來。例:

 char greeting[50] = "hello,and" "how are" "you";

等價於:

 char greeting[50] = "hello,and how are you";

字符串常量屬於靜態存儲類。靜態存儲是指如果在一個函數中使用字符串常量,即使是多次調用了這個函數,

該字符串在程序的整個運行過程中只存儲一份。整個引號的內容作為指向該字符串存儲位置的指針。這一點與

把數組名作為指向數組存儲位置的指針類似。

2.字符串數組及其初始化

初始化例子:

  char m[40] = "hello,world";  //定義字符串數組時必須指定數組大小(整型常量),在指定大小時,要確保數組的大小比預定的大一個,因為編譯器會自動添加'\0'。

                                         //多余的元素會初始化為'\0'



  char m={'h','e','l','\0'};  //注意標志結束的空字符,若沒有它,得到的只是一個字符數組而不是字符串

3.利用char指針定義字符串

   char *m = "hello,world"; //自動添加'\0'

  注意:此時字符串指針m指向字符串常量,不成用*(m+1)='o'修改此常量,因為這個字符串常量放在常量區不能被修改

4.數組和指針

數組形式和指針形式有什么不同呢?

   數組形式: char m[40] = "hello,world";   m是個指針常量

   指針形式: char *m = "hello,world";  m是個指針變量

數組形式:

     編譯器會把數組名m看作是數組首元素的地址&m[0]的同義詞,m是個地址常量。可以用m+1來標識數組里的下一個元素,但不能使用++m,增量運算符只能在變量前使用, 而不能在常量前使用。

     m[40]在計算機內存中被分配一個有40個元素的數組(其中每個元素對應一個字符,還有一個附加的元素對應結束的空字符'\0')。每個元素都被初始化為相應的字符。  

         通常,被引用的字符串存儲在可執行文件的數據段部分;當程序被加載到內存中時,字符串也被加載到內存中,把被引用的字符串復制到數組中
指針形式:

     指針形式(*m)也會在靜態存儲區為字符串預留空間。此外,一旦程序開始執行,還要為指針變量m另外預留一個存儲位置,以在該指針變量中能夠存儲字符串的地址。
      m指向字符串的第一個字符,可用++m指向第二個字符。  指針m是個變量。    

c/c++中使用字符串的頻率還是比較高的,下面就字符串的不同定義及其使用方法做一些對比

字符串一般有以下三種定義方法:

1、char *p="hello";

2、char str[6]="hello";

3、string s="hello";

【第一種字符串】:這種定義方式會被編譯器默認為字符串常量,自行默認為是不會被改變的,所以編譯時會被存儲在一個只讀的數據段中,嘗試對這種類型字符串的改變是不被允許的。

如:

char *p="hello";
p[1]='x';

這個時候,輸出字符串就會爆出"段錯誤"(我這里的實驗平台是linux,會和windows有所不同),因為修改了內存只讀區域,這是不允許的;

【第二種和第三種字符串】:這種定義方式實際上是把存在只讀數據段中的字符串復制到了一個字符數組中,這種字符串中的任意字符都可以被隨便改變,這里不再做出演示。

*注意一下情況:

char *str1="hello";
char *str2="hello";

這個時候,str1和str2指向的其實是同一個內存地址,可以用一下語句進行驗證:

if(str1==str2)
cout<<"str1=str2"<<endl;

*linux下定義字符串爆出warning的處理方法:在定義字符串時加上const限定修飾符,告訴編譯器這是常量,否則g++/gcc都會認為是變量,所以會爆出warning

在gcc命令行中,我想定義一個字符串,例如-Dname = Mary,然后在源代碼中我想要printf(“%s”,name);打印瑪麗。
我該怎么辦呢?
兩個選項。首先,逃避引號,使殼不會吃它們:

gcc -Dname="Mary"

或者,如果你真的想要-Dname = Mary,你可以把它串起來,雖然它有點怪。

include <stdio.h>

define STRINGIZE(x) #x

define STRINGIZE_VALUE_OF(x) STRINGIZE(x)

int main(int argc, char *argv[])
{
printf("%s", STRINGIZE_VALUE_OF(name));
}

請注意,STRINGIZE_VALUE_OF會很樂意評估宏的最終定義。

Sample code:

main()
{
printf("%d\n", MARCO);
// printf("%s\n", MARCO);
}

When I try to use gcc -D option, I found the following command works:

gcc -D MARCO=12345 test.c

but when I change 12345 to a string:

gcc -D MARCO=abcde test.c

an error occurs:

error: ‘abcde’ undeclared (first use in this function)

I have tried -DMARCO=abcde, -DMARCO="abcde", -D MARCO="abcde"; all failed with that error.

Does this -D option only support integers?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM