1,基本語法
1,定義一個char字符:
char hehe='a'; //單引號
2,定義一個由char字符組成的數組:
char daqing[] = "abcd"; char daqing[] = { 'a','b','c','d' }; //兩個效果一樣,這兩個都是和字符相關的實體,不是指針,但是因為是數組,數組的取值規則是,存儲第一個元素的地址,依次向后遍歷直到找到\0,所以,daqing這個變量是地址(盡管存儲的是地址,但是daqing不是指針類型,是實體),它指向字符a,取值的時候直接取daqing[0]
如何遍歷這兩個char數組?
方法一,直接按照下標拿值 for (int k = 0; k < sizeof(daqing);k++) { printf("address---> %c \n", daqing[k]); }
方法二,按地址拿值 char * test = &daqing[0]; //先定義一個指向頭的指針,指針內容是第一個元素的地址 for (int k = 0; k < sizeof(daqing);k++) { printf("address--->*test---> %c \n", *test); test++; } //*test的意思的把地址翻譯為內容,test++表示拿下一個挨着的地址
3,定義char*
話說,char*是個啥,如果寫char * hehe="abc";有些環境要這么寫才行(const char * hehe="abc";)表示定義一個char指針名字叫hehe,hehe指向靜態文本區(就是const靜態區)數組的“abc"的首地址,因為是靜態區,所以,如果你后期想把”abc“改成”cba“,抱歉,那不可以!除非你重新把hehe指向”cba",此時之前創建的"abc"貌似是還沒有銷毀,得等到程序執行完畢以后由系統回收。聽起來用途也不大廣泛的樣子。不過還是說一下。
const char* hehe = "abc"; //定義一個指針指向靜態區的“abc"的頭一個元素的a的地址,這個用法還是少用點 const char* str[] = { "Hello", "C++", "World" }; //這個就比較厲害了,這個和上一個不一樣,這個是定義了一個數組,數組的元素是指向靜態區的指針,相當於把好多個hehe放到了一個數組中 如何遍歷: for (int j = 0; j < 3;j++) { printf("value %c ",str[j]); }
雖然要慎用,但是也不是說一點用也沒有,個人目測,int main(int argc, char *argv[]) {...}里面的argv就是指針數組這樣的結構,argv第0個參數是程序名,argc是參數的個數。
看一個把char* str[]當作參數傳遞的例子,argv也可以這么用:
#include <iostream> using namespace std; void test(char *xc[]); //形參聲明了這是一個內含一堆char指針的數組 int main() { char *hehe[] = { "abc","bcd" }; test(hehe); return 0; } void test(char *xc[]) { cout << xc[0] << endl; }
讓值得注意的是,
#include <iostream> using namespace std; int main() { //定義一個指針指向單個字符,如下寫法是正確的: char t2='2'; char *t22 = &t2; //但是這樣的寫法是報錯的: char *t22 = 'a'; //雖然char指針不能指向單個字符,卻可以指向char數組,奇了怪了 char *t3 = "abc"; return 0; }
后來查閱了一下,雙引號“abc”做了三件事:1,申請了空間(在常量區),存放了字符串 ;2. 在字符串尾加上了'/0' ;3.返回地址;
所以說char *t3=“abc”的時候,t3就有了地址,但是‘a'存在於內存中只是一串ascii碼,沒有被儲存起來,沒有地址。所以不能直接賦值。
盡管這樣語法是正確的,但是這樣的寫法很詭異,為什么很詭異,看例子
const char *aa = "123"; //定義一個char字符(不是數組)的指針,指向一個靜態區的一個char數組的第一個元素 printf("%p,%p\n", aa,"123"); //驗證一下,aa確實是地址,並且和“123”地址一模一樣 cout <<*aa << endl; //char數組用cout打印一般能打印出來全部的元素,但是*aa不行,只能打印出1來,因為我們是用char字符的指針存儲了char數組的地址,感覺上就不大常用
就好比:
aa是const char * 指針,指向地址0x11,0x11上放了一個字符“a",不管其他地址上是什么,我char字符只拿0x11上一個字節的內容。
bb是const char * 指針,指向地址0x20,0x20上放了字符“d",0x21上放了字符“e",0x22上放了字符“f",0x23上放了字符“\0",我如果按照char 指針的規則來拿,我只能拿到”d",但是我如果按照char數組的規則來拿,先拿到了”d”,又拿到了“e","f",遇到\0停止了,所以我能拿到def。
2,順帶說一聲c++的存儲區
一個由c/C++編譯的程序占用的內存分為以下幾個部分,感謝原作者
1、棧區(stack)—由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於
數據結構中的棧。
2、堆區(heap)—一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收。注意它與數據
結構中的堆是兩回事,分配方式倒是類似於鏈表,呵呵。
3、全局區(靜態區)(static)—全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態
變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。程序結束后由系統
釋放。
個人理解,僅供參考:
int daqing=3; //棧里有個daqing的名字和地址,指向堆里的一個整數3;如果是在main上面,那就是全局初始化區(靜態區)
int b; //main下的,棧區
char *p2; //棧
static int c=0; //全局(靜態)初始化區
char *p2; //棧
p2 = (char*)malloc(20); //分配得來得20字節的區域就在堆區。
3,補充,char數組和char字符不一樣
區別:
char hehe[]="ab"; printf("%p,%p\n", hehe,&hehe[0]); //hehe打印出來是數組中第一個元素的內存地址,, hehe和hehe[0]地址一樣,所以使用char數組的時候要注意,即使不加&,它本身就是地址,類似於指針 char aa='a'; //aa存儲的是字符“a”,和int是一個道理,aa不是指針,是個值
拿傳遞參數來說明使用char和char數組的區別:
char
using namespace std; int test(char *xc); int main() { char t2='2'; test(&t2); //此處相當於int *xc=&t2;int型指針xc這個變量現在指向的是t2的地址 printf("quanju %c\n", t2);//打印為:2 return 0; } int test(char *xc) { char t1 = '1'; *xc = t1; //*xc是個值,*t1也是個值,通過修改xc指向的內存的值,也修改了外部變量 cout << *xc << endl; printf("jubu %c\n",*xc); return 0; }
char數組
#include <iostream> using namespace std; int test(char *xc); int main() { char t2[]="2"; test(t2); //此處相當於int *xc=t2(t2本身就是指向它第一個元素的地址);int型指針xc這個變量現在指向的是t2的地址 printf("quanju %c\n", t2[0]);//打印為:2 return 0; } int test(char *xc) {char t1[] = "1"; *xc = *t1; //*xc是個值,*t1也是個值,通過修改xc指向的內存的值,也修改了外部變量 printf("jubu %c\n",xc[0]); return 0; }