1. 程式人生 > >2.2 指標的計算

2.2 指標的計算

1. 1 + 1 = 2?

給一個指標 加 1,表示要讓指標指向下一個變數
如果指標不是指向一片連續分配的空間,這種運算沒有意義

#include<stdio.h>

int main(void)
{
    // char 陣列 
    char ac[] = {0, 1, 2, 3, 4, 5, 6};
    char *p = ac;

    printf("p=%p\n", p); // p=000000000022FE40
    printf("P+1=%p\n", p + 1); // P+1=000000000022FE41
    printf("sizeof(char)=%d\n", sizeof(char
)); // sizeof(char)=1 // int 陣列 int ai[] = {1, 2, 3, 4, 5}; int *q = ai; printf("q=%p\n", q); // q=000000000022FE10 printf("q+1=%p\n", q + 1); // q+1=000000000022FE14 printf("sizeof(int)=%d\n", sizeof(int)); // sizeof(int)=4 printf("*(q+1)=%d\n", *(q + 1)); // *(q+1)=2 即 *(q + 1) = ai[1] return 0; }

2. 指標的算術運算

可以給指標 加 減一個整數、遞增(++)、遞減(–)、兩個指標相減

#include<stdio.h>

int main(void)
{
    char ac[] = {0, 1, 2, 3, 4, 5, 6, 7};
    char *p = &ac[0];
    char *p1 = &ac[5];

    printf("p =%p\n", p); // p =000000000022FE20
    printf("p+1=%p\n", p + 1); // p+1=000000000022FE21
    printf("p1-p=%d\n", p1-p); // p1-p=5
int ai[] = {1, 2, 3, 4, 5, 6, 7, 8}; int *q = ai; int *q6 = &ai[6]; printf("q =%p\n", q); // q =000000000022FE20 printf("q6=%p\n", q6); // q6=000000000022FE38,十六進位制 printf("q6-q=%d\n", q6-q); // q6-q=6 return 0; }

3. *p++

  • 先計算 ++,在計算 *
  • 取出 p 所指的那個資料,再將p移到下一個位置
  • 用於陣列類的連續空間操作
  • 在某些CPU上,可以直接被翻譯成一條彙編指令
#include<stdio.h>

int main(void)
{
    char ac[] = {0, 1, 2, 3, 4, 5, 6, -1};
    char *p = &ac[0];
    int i;
    for(i = 0; i < sizeof(ac)/sizeof(ac[0]); i++){
        printf("%d\n", ac[i]);
    }

    printf("-------------\n");

    // 假設 -1 表示結束
    while( *p != -1){
        printf("%d\n", *p++);
    }

    return 0;
}

這裡寫圖片描述

4. 指標比較

<, <=, == , >, >=, != 都可以對指標做
可以比較在記憶體中的地址
陣列中的單元的地址肯定是 現行遞增的

5. 0地址

  • 0地址通常是不能隨便碰的地址,所以你的指標不應該具有 0值
  • 可以用0地址來表示特殊的事:
    • 返回的指標是無效的
    • 指標沒有被真正初始化
  • NULL是一個預定義的符號,表示0地址
    • 有的編譯器不願意用0來表示0地址

6.指標的型別

  • 無論指向什麼型別,所有的指標的大小都是一樣的,因為都是地址
  • 指向不同型別的指標 不能直接互相賦值,這是為了避免用錯指標
#include<stdio.h>

int main(void)
{
    char ac[] = {0, 1, 2, 3, 4, 5, 6, -1};
    char *p = &ac[0];

    int ai[] = {0, 1, 2, 3, 4, 5, 6};
    int *q = ai;

//  q = p; //   [Error] cannot convert 'char*' to 'int*' in assignment

    return 0;
}

7. 指標的型別轉換

  • void* 表示不知道指向什麼東西的指標
  • 指標也可以轉換型別
#include<stdio.h>

int main(void)
{
    int i = 5;
    int *p = &i;
    // 沒有改變p所指的變數的型別,只是換了個看待p所指變數的方式
    // 不再當它是 int,認為是 void
    void* q = (void*)p; 

    return 0;
}

8.指標的用途

  • 需要傳入比較大的資料時 用作引數
  • 傳入陣列後,對陣列做操作
  • 函式返回不止一個結果,需要用函式來修改不止一個變數
  • 動態申請的記憶體

9. 動態分配記憶體

9.1 malloc

#include<stdlib.h>
void* malloc(size_t size);
  • malloc申請的空間的大小是以位元組為單位的
  • 返回的型別是 void*,需要型別轉換為 自己需要的型別,比如 (int*)malloc(n * sizeof(int))
  • 如果什麼失敗則返回0,或者叫做NULL

輸入資料時,先告訴你個數n,再輸入n個數字,要記錄每個資料
C99可以用變數n做陣列定義的大小,C99之前呢?用 int a = (int )malloc(n * sizeof(int));

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    int number;
    int* a;
    printf("輸入數量:");
    scanf("%d", &number);

    a = (int*)malloc(number * sizeof(int));
    int i;
    for(i = 0; i < number; i++){
        scanf("%d", &a[i]);
    }

    for(i = number - 1; i >= 0; i--){
        printf("%d ", a[i]);
    }

    free(a);


    return 0;
}
#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    //你的系統能給你多大空間?
    void *p;
    int cnt = 0;
    while((p=malloc(100 * 1024 * 1024))) {
        cnt++;
    }

    printf("分配了%d00MB的空間\n", cnt); // 分配了10300MB的空間


    return 0;
}

9.2 free

  • 把申請得來的空間還給系統
  • 只能還申請來的空間的首地址

常見問題

  • 申請了沒free,長時間執行記憶體逐漸下降
    • 新手:忘了
    • 老手:找不到合適的free的時機
  • free過了再free
  • 地址變了,直接去free