c++ 踩坑大法好 char字符,char數組,char*


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;
}

 


免責聲明!

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



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