天天看點

C語言從入門到精通——指針基礎

指針和記憶體單元

指針: 位址。

記憶體單元: 計算機中記憶體最小的存儲機關。——記憶體單元。大小一個位元組。 每一個記憶體單元都有一個唯一的編号(數)。

     稱這個記憶體單元的編号為 “位址”。

指針變量:存位址的變量。      

指針定義和使用:

int a = 10;

int *p = &a;      int* p;--- windows; int *p ---Linux       int * p ;

int a, *p, *q, b;

*p = 250;     指針的 解引用。 間接引用。

*p : 将p變量的内容取出,當成位址看待,找到該位址對應的記憶體空間。

  如果做左值: 存資料到空間中。

  如果做右值: 取出空間中的内容。


任意“指針”類型大小:

  指針的大小與類型 無關。 隻與目前使用的平台架構有關。   32位:4位元組。   64位: 8位元組。      
using namespace std;
int main() {
    int a=10;
    int *p = &a;
    printf("指針位址%d\n",p);
    printf("存指針位址:%d\n",&p);
    printf("解引用:%d\n",*p);
    printf("a的位址%d\n",&a);
    return 0;
}      

野指針:

1) 沒有一個有效的位址空間的指針。

int *p;

  *p = 1000;

2)p變量有一個值,但該值不是可通路的記憶體區域。
  
  int *p = 10;

  *p = 2000;

【杜絕野指針】      

空指針:

int *p = NULL; #define NULL ((void *)0)

*p 時 p所對應的存儲空間一定是一個 無效的通路區域。      

萬能指針/泛型指針(void *):

可以接收任意一種變量位址。但是,在使用【必須】借助“強轉”具體化資料類型。

  char ch = 'R';

  void *p;  // 萬能指針、泛型指針
  
  p = &ch;

  printf("%c\n", *(char *)p);      

const關鍵字:

修飾變量:

const int a = 20;

int *p = &a;

*p = 650;

printf("%d\n", a);


修飾指針:
const int *p;
  可以修改 p
  不可以修改 *p。
int const *p;
  同上。
int * const p;
  可以修改 *p
  不可以修改 p。
const int *const p;
  不可以修改 p。
  不可以修改 *p。
總結:const 向右修飾,被修飾的部分即為隻讀。
常用:在函數形參内,用來限制指針所對應的記憶體空間為隻讀。      

指針和數組:

數組名:  
  【數組名是位址常量】 --- 不可以被指派。   ++ / -- / += / -= / %= / /=  (帶有副作用的運算符)

  指針是變量。可以用數組名給指針指派。 ++ -- 

取數組元素:

  int arr[] = {1,3, 5, 7, 8};

  int *p = arr;  

  arr[i] == *(arr+0) == p[0] == *(p+0)

指針和數組差別:

  1. 指針是變量。數組名為常量。

  2. sizeof(指針) ===》 4位元組 / 8位元組

     sizeof(數組) ===》 數組的實際位元組數。

指針++ 操作數組:

  int arr[] = { 1, 2, 4, 5, 6, 7, 8, 9, 0 };
  int *p = arr;   

  for (size_t i = 0; i < n; i++)
  {
    printf("%d ", *p);
    p++;  // p = p+1;   一次加過一個int大小。 一個元素。
  }

  p的值會随着循環不斷變化。列印結束後,p指向一塊無效位址空間(野指針)。      

指針加減運算:

資料類型對指針的作用:

1)間接引用:
    決定了從指針存儲的位址開始,向後讀取的位元組數。  (與指針本身存儲空間無關。)
  2)加減運算:
    決定了指針進行 +1/-1 操作向後加過的 位元組數。
指針 * / % : error!!!
指針 +- 整數:
  1) 普通指針變量+-整數
    char *p; 列印 p 、 p+1  偏過 1 位元組。
    short*p; 列印 p 、 p+1  偏過 2 位元組。
    int  *p; 列印 p 、 p+1  偏過 4 位元組。   
  2)在數組中+- 整數
    short arr[] = {1, 3, 5, 8};
    int *p = arr;
    p+3;      // 向右(後)偏過 3 個元素
    p-2;      // 向前(左)偏過 2 個元素
  3)&數組名 + 1
    加過一個 數組的大小(數組元素個數 x sizeof(數組元素類型))
指針 +- 指針:
  指針 + 指針: error!!!
  指針 - 指針:
    1) 普通變量來說, 文法允許。無實際意義。【了解】

    2) 數組來說:偏移過的元素個數。      
#include <iostream>
using namespace std;
int main() {
    int a[]= {3,2};
    int *p = a;
    printf("指針位址%d\n",p);
    printf("存指針位址:%d\n",&(p));
    printf("解引用:%d\n",*p);
    printf("a的位址%d\n",&a);
    printf("存指針位址:%d\n",*(p+1));
    return 0;
}      

指針實作 strlen 函數:

char str[] = “hello”;

char *p = str;

while (*p != ‘\0’)

{

p++;

}

p-str; 即為 數組有效元素的個數。

指針比較運算:

1) 普通變量來說, 文法允許。無實際意義。
2) 數組來說:    位址之間可以進行比較大小。
        可以得到,元素存儲的先後順序。
3) int *p;
    p = NULL;       // 這兩行等價于: int *p = NULL;
    if (p != NULL)
    printf(" p is not NULL");
    else 
    printf(" p is NULL");      

指針數組:

一個存儲位址的數組。數組内部所有元素都是位址。

1)

int a = 10;

int b = 20;

int c = 30;

int *arr[] = {&a, &b, &c}; // 數組元素為 整型變量 位址
2) 

  int a[] = { 10 };
  int b[] = { 20 };
  int c[] = { 30 };

  int *arr[] = { a, b, c }; // 數組元素為 數組 位址。 

指針數組本質,是一個二級指針。

二維數組, 也是一個二級指針。      

多級指針:

int a = 0;

int *p = &a;          一級指針是 變量的位址。

int **pp = &p;        二級指針是 一級指針的位址。

int ***ppp = &pp;     三級指針是 二級指針的位址。  

int ****pppp = &ppp;      四級指針是 三級指針的位址。  【了解】      
多級指針,不能  跳躍定義!
對應關系:
ppp == &pp;     三級指針  
*ppp == pp == &p;       二級指針
**ppp == *pp == p == &a       一級指針
***ppp == **pp == *p == a       普通整型變量
*p : 将p變量的内容取出,當成位址看待,找到該位址對應的記憶體空間。
  如果做左值: 存資料到空間中。
  如果做右值: 取出空間中的内容。      

繼續閱讀