第一章. 指針基礎(chǔ)知識(shí)

1. 內(nèi)存地址和內(nèi)存空間

學(xué)習(xí)指針的相關(guān)知識(shí),首先需要了解下內(nèi)存。我們通常所說的內(nèi)存,往往指的是內(nèi)存空間。其實(shí)內(nèi)存是由內(nèi)存地址和內(nèi)存空間共同組成的,且內(nèi)存地址和內(nèi)存空間是一一對(duì)應(yīng)的。

內(nèi)存地址是一個(gè)編號(hào),代表一個(gè)內(nèi)存空間的位置。
內(nèi)存空間是存儲(chǔ)數(shù)據(jù)的空間,真正保存數(shù)據(jù)的地方。
在計(jì)算機(jī)中存儲(chǔ)器的容量是以字節(jié)為基本單位的。也就是說一個(gè)內(nèi)存地址代表一個(gè)字節(jié)(8bit)的存儲(chǔ)空間。

內(nèi)存地址對(duì)應(yīng)內(nèi)存空間.png

有個(gè)非常形象的比喻:
內(nèi)存就像小區(qū)房子一樣,內(nèi)存地址代表房子的門牌號(hào),內(nèi)存空間是房子內(nèi)居住的空間。
已經(jīng)被出售了的,代表空間被申請(qǐng)占用了;
已經(jīng)辦理入住的,代表空間被數(shù)據(jù)寫入;
正在出售的,代表此空間空閑;

2. 指針相關(guān)表示方法

  • 2.1 指針,指向某空間的標(biāo)記,比如:

    char *charPointer —> charPointer是指向 char 類型的指針。char 內(nèi)存中占用一個(gè)字節(jié)內(nèi)存空間,charPointer指向了這個(gè)字節(jié)的內(nèi)存地址

    int *intPointer —> intPointer是指向 int 類型的指針。int 內(nèi)存中占用四個(gè)字節(jié)內(nèi)存空間,ntPointer指向了這個(gè)四個(gè)字節(jié)中首字節(jié)的內(nèi)存地址。

  • 2.2 取地址
    符號(hào) &,可以幫助我們獲取相關(guān)內(nèi)存中的地址。
    指針就是先申請(qǐng)內(nèi)存空間,然后把指向這個(gè)數(shù)據(jù)內(nèi)存的首地址存入申請(qǐng)的內(nèi)存空間。
    所以指針必須初始化才有意義。

 int a = 1;

 int *d ; //申請(qǐng)一個(gè)可以保存 int 類型內(nèi)存地址的指針
 d = &a;// 把 a 的地址賦值給指針

 printf("%d \n", a); // log結(jié)果:1
 printf("%p \n", &a); //log結(jié)果:0x7ffeefbff59c 
 printf("%lu \n", sizeof(a)); //log結(jié)果:4

 printf("%p \n", d); //log結(jié)果:0x7ffeefbff59c
 printf("%lu \n", sizeof(d)); //log結(jié)果:8
  • 2.3 解引用
    我們已經(jīng)知道指針的內(nèi)存空間中保存了相關(guān)的數(shù)據(jù),那么怎么來(lái)使用這個(gè)數(shù)據(jù)呢?這里需要的就是解引用,也就是間接訪問。
    需要注意的是:
    NULL 指針 :什么都沒有指向的指針(默認(rèn) NULL = 0)
 int a = 1;
 int *d ; 
 d = &a;

printf("%d \n", a); // log結(jié)果:1

*d = 5;  //這里就是解引用(間接訪問) :* 這個(gè) * 是解引用指針
printf("%d \n", a); // log結(jié)果:5

3. 指針的相關(guān)運(yùn)算

通過取地址,指針,解引用……相關(guān)的表示,我們衍射出很多相關(guān)的運(yùn)算

  • 3.1 通過指針操作相關(guān)的變量
 int a = 12;
 int *d = &a;// 創(chuàng)建指針 指向a的地址
        
*d = 10 - *d;//  這里其實(shí)就修改了a變量

 printf("%d \n",a); // log 結(jié)果:-2
//先取地址 然后解引用
 *&a = 25;// 這行等價(jià)于 a = 25;
 printf("%d \n",a);// log 結(jié)果:25
 printf("%p \n",&a);// 取a 的地址::0x7ffeefbff59c
 //對(duì)這個(gè)地址數(shù)值進(jìn)行操作
 *(int *)0x7ffeefbff59c = 20; // (int *)0x7ffeefbff59c ->代表指針常量,這個(gè)是把內(nèi)存地址強(qiáng)轉(zhuǎn)成一個(gè)指針

 printf("%d \n",a);//打印結(jié)果 :a = 20;
  • 3.2 多級(jí)指針
    多級(jí)指針是指,把一個(gè)變量的地址賦值給一個(gè)指針,然后把這個(gè)指針的地址又賦值給新的指針……

    多級(jí)指針的解引用,也是一層層通過相關(guān)的地址找到最終變量,然后才能對(duì)變量進(jìn)行相關(guān)操作

 int a = 12;
 int *b ;
 b = &a;

 int **c;//指向指針的指針 :指向指針的地址
 c = &b;
        
/* 解引用: **
第一個(gè)* 指向b 的內(nèi)存地址,得到指針b
第二個(gè)* 指向a 的內(nèi)存地址,得到變量a
*/
  **c = 25;

  printf("%d \n",a);//打印結(jié)果 :a = 25;
  • 3.3 練習(xí)指針的++,--
char c1,c2,c3;
char *cp;
//定義初始化函數(shù)
void setup() {
     c1 = 'a';
     c2 = 'f';
     c3 = 'c';
  
   cp = &c1;
}

int main(int argc, const char * argv[]) {

 setup();
 printf("%c : %c : %c \n",c1,c2,c3);//a : f : c 
 printf("%p : %p : %p \n",&c1,&c2,&c3);//0x100001030 : 0x100001031 : 0x100001032 
 printf("%p : %p \n",&c1,cp);//獲取 c1 cp 地址:0x100001030 : 0x100001030
 printf("%p \n",&cp);//指針的地址:0x100001038
 printf("%c \n",*cp);//指針指向的地址:a
 printf("%c \n",*cp + 1);//指針指向的地址:b ;原因:a的asc值97 ,97+1 = 98 (b的asc值)
 printf("%p : %p \n",cp + 1,&c2);//指針指向的地址:0x100001031 : 0x100001031 
 printf("%c \n",*(cp + 1));//指針指向的地址:f : 原因:指針指向的內(nèi)存地址 + 1,指向了下一個(gè)byte的內(nèi)存
 printf("%p : %p \n",++cp,&c2);//0x100001031 : 0x100001031

// 練習(xí) // 結(jié)果:
  setup();
  printf("%c \n",*cp);//a
  printf("%c \n",++*cp);//b 
        
  setup();
  printf("%c \n",*cp++);//a
        
  setup();
  printf("%c \n",*(cp + 1));//f

  setup();
  printf("%c \n",++*cp++);//b

  setup();
  printf("%c \n",++*++cp);//g

}

4. 指針與字符串

字符串指針->指向的是字符串第一個(gè)字符的內(nèi)存地址;
字符串都是以"\0"結(jié)尾;

計(jì)算字符串長(zhǎng)度的demo:

// 計(jì)算字符串長(zhǎng)度
int my_strlen(char *string){
    int length = 0; 
    while (*string++ != '\0') {
        length++;
    }
    return length;
}

int main(int argc, const char * argv[]) {

        char *name = "bill gates";  //指向字符串:指向的是第一個(gè)字符;
        printf("%s \n",name);//bill gates 

        unsigned long length = strlen(name);  // 字符長(zhǎng)度 c系統(tǒng)自帶函數(shù)
        printf("%lu \n",length);//10
     
        //自定義函數(shù)
        int myLength = my_strlen(name);
        printf("%d \n",myLength);//10
}

查找字符串中的某個(gè)字符demo

//查找字符串
int find_char(char **strings,char word,int count){ 
    char *string ;
    char character;
    int  num = 0;
    while ((string = *strings++) && num++ < count) {
        while ((character = *string++ ) != '\0') {
            if ( character == word ){
                return 1;
            }else{
                printf("繼續(xù)查找……%c \n",character);
            }
        }
    }
    return 0;
}
int main(int argc, const char * argv[]) {

        char *s0 = "zero", s1 = "first", s2 = "second",s3 = "third",*s4 = " ";
     
        int total = 5;
        char *strs[total];
        strs[0] = s0;
        strs[1] = s1;
        strs[2] = s2;
        strs[3] = s3;
        strs[4] = s4;
    
        char word = 'a';    //查找詞
        
        if ( find_char(strs, word,total) ){
            printf("find_char :%c \n",word);
        }else{
            printf("unfind_char :%c \n",word);
        }
}

5. 指針的運(yùn)算常在數(shù)組中使用

算數(shù)運(yùn)算:指針 +(-) 整數(shù) ,指針 - 指針(只限于指向同一數(shù)組的指針)
單獨(dú)的兩個(gè)指針進(jìn)行 加減乘除 是沒有意義的

關(guān)系運(yùn)算(只限于指向同一數(shù)組的指針): >, >=, <, <=, !=, ==

// 遍歷數(shù)組
void logArray(char arr[],int count){
    for(int i = 0 ;i < count ; i++){
        printf("%d : %c \n",i,arr[i]);
    }
}
int main(int argc, const char * argv[]) {
   char *cp;
   int total = 5;
   char characters[total];
 /*cp < &characters[total];
  指針的邏輯比較
*/ 
    for (cp = & characters[0]; cp < &characters[total]; cp++) {
       *cp = 'a';
    }
        
    logArray(characters, total);
        
     char * cBegin = &characters[0];
     char * cEnd = &characters[total];
        
      for (cp = cEnd; cp >= cBegin; cp--) {
            *cp = 'b';
      }
        
     logArray(characters, total);

 /*long count = cEnd -cBegin;
 指針的加減,判斷數(shù)組中元素間隔的距離
*/ 
      long count = cEnd -cBegin;
      printf("array count : %ld \n",count);
}

6. 指針和函數(shù)

  • 6.1 函數(shù)的返回值可以是指針
int* find_intValue(int arr[] ,int arr_count ,int value ){
    
    for (int i = 0 ; i<arr_count; i++) {
        if (arr[i] == value){
            return &arr[i];
        }
    }
    return  NULL;
}
int main(int argc, const char * argv[]) {
//  數(shù)組中查找指定元素,找到返回元素指針,否則返回 NUL
        int total = 5;
        int arr[total];
        for(int i = 0 ;i < total ; i++){
            arr[i] = i;
        }
        
        int *result = find_intValue(arr, total, 3);
        if (result != NULL) {
            printf("find Value \n");
        }else{
            
            printf("can not find Value \n");
        }
}
  • 6.2 函數(shù)的參數(shù)也可以是指針
// 數(shù)據(jù)交換
void swap_0(int a ,int b){
    int temp = a;
    a = b;
    b = temp;
}
void swap_1(int *a ,int *b){
    int temp = *a;
    *a = *b;
    *b = temp;
}
int main(int argc, const char * argv[]) {
   //交換
        int m = 10;
        int n = 20;
        
// 傳值 操作,并不能完成數(shù)據(jù)的交換 
//參數(shù)把數(shù)值拷貝一份,函數(shù)內(nèi)部進(jìn)行了交換,不會(huì)影響到外部;
        printf("swap_0交換前 m= %d : n= %d \n",m,n);
        swap_0(m, n);
        printf("swap_0交換后 m= %d : n= %d \n",m,n);
// 傳址 操作,才能完成數(shù)據(jù)的交換
//參數(shù)把地址拷貝一份,函數(shù)內(nèi)部根據(jù)地址獲取變量進(jìn)行了交換,所以在內(nèi)存中數(shù)據(jù)發(fā)生了交換
        printf("swap_1交換前 m= %d : n= %d \n",m,n);
        swap_1(&m, &n);
        printf("swap_1交換后 m= %d : n= %d \n",m,n); 

/*log結(jié)果:傳值操作和傳址操作是明顯不同的
swap_0交換前 m= 10 : n= 20 
swap_0交換后 m= 10 : n= 20 
swap_1交換前 m= 10 : n= 20 
swap_1交換后 m= 20 : n= 10 
*/
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 指針是C語(yǔ)言中廣泛使用的一種數(shù)據(jù)類型。 運(yùn)用指針編程是C語(yǔ)言最主要的風(fēng)格之一。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu); ...
    朱森閱讀 3,612評(píng)論 3 44
  • C語(yǔ)言是面向過程的,而C++是面向?qū)ο蟮?C和C++的區(qū)別: C是一個(gè)結(jié)構(gòu)化語(yǔ)言,它的重點(diǎn)在于算法和數(shù)據(jù)結(jié)構(gòu)。C程...
    小辰帶你看世界閱讀 1,017評(píng)論 0 6
  • 1. 變量 不同類型的變量在內(nèi)存中占據(jù)不同的字節(jié)空間。 內(nèi)存中存儲(chǔ)數(shù)據(jù)的最小基本單位是字節(jié),每一個(gè)字節(jié)都有一個(gè)內(nèi)存...
    C語(yǔ)言學(xué)習(xí)閱讀 1,357評(píng)論 0 4
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,639評(píng)論 1 32
  • 前言:復(fù)雜類型說明 要了解指針,多多少少會(huì)出現(xiàn)一些比較復(fù)雜的類型,所以我先介紹一下如何完全理解一個(gè)復(fù)雜類型,要理解...
    有理想有暴富的小青年閱讀 635評(píng)論 0 4

友情鏈接更多精彩內(nèi)容