Linux C - 指標

相信很多人搞不懂指標,現在以我知道的方式來說明。

基本知識:
& 使用這變數的指標,也就是取指標
* 依這變數的指標型態取值,也就是取值 (但使用在func宣告或變數宣告,則代表指標型態)

字串指標


    char buf[512]; // 為實體字串空間


    char *_buf; // 為字串指標

直接使用 buf 取得字串指標,並可用 _buf 接起來,如下:

    char buf[512];
    char *_buf;
    _buf = buf;


buf[3],指的是 buf 的 0,1,2,3 第4個字元 (從0開始),等同於 *(buf+3)
(字串的 buf[3] 與取值意思相同)

    char buf[] = "abcdefg";
    printf("%c\n", buf[3]);
    === 執行結果 ===
    d

直接使用 buf ,指的是使用這個實體空間的頭,為指標型態,等同於 &buf[0]


將 buf 或 _buf 傳入 func 內,皆會直接改到原始字串


數字指標


    int val; // 為實體數字空間


    int *_val; // 為數字指標

使用 &val 取得數字指標,並可用 _val 接起來,如下:

    int val;
    int *_val;
    _val = &val;


將 _val 傳入 func,在func內使用,需加*號,如下:

void func1(int *_val) {
printf("1 => %d\n", *_val);
*_val = 2;
}
void func2(int val) {
printf("2 => %d\n", val);
val = 3;
}
void main() {
int val = 1;
func1(&val);
printf("main1 => %d\n", val);
func2(val);
printf("main2 => %d\n", val);
}
=== 執行結果 ===
1 => 1
main1 => 2
2 => 2
main2 => 2


將 &val 傳入 func,會改到原始值
將 val 傳入 func,不會改到原始值


結構指標

宣告方法如下:

    struct TYPE {
    char buf[32];
    char *_buf;
    int val;
    int *_val;
    }

使用方法如下:

    struct TYPE type; // 為實體空間
    struct TYPE *_type; // 為指標型態
    _type = &type;
    printf("%s, %d\n", type.buf, _type->val);

實體要使用 . 點這個符號
指標要使用 -> 減號和大於 這兩個符號


實例

字串實例:

void func(char *a, char **b, char **c) {
printf("=== func a start ===\n");
printf("%p, %c\n", a, *a); // 0x55d0ff9f855a, a
printf("%p, %c\n", a+1, *(a+1)); // 0x55d0ff9f855b, b
printf("%p, %c\n", a+2, *(a+2)); // 0x55d0ff9f855c, c
printf("\n");
printf("%p, %c\n", &a[0], a[0]); // 0x55d0ff9f855a, a
printf("%p, %c\n", &a[1], a[1]); // 0x55d0ff9f855b, b
printf("%p, %c\n", &a[2], a[2]); // 0x55d0ff9f855c, c
printf("=== func a end ===\n");
printf("=== func b start ===\n");
printf("%p, %p, %c\n", b, *b, **b); // 0x7ffd13793718, 0x55d0ff9f855a, a
printf("%p, %p, %c\n", b+1, (*b)+1, *((*b)+1)); // 0x7ffd13793720, 0x55d0ff9f855b, b
printf("%p, %p, %c\n", b+2, (*b)+2, *((*b)+2)); // 0x7ffd13793728, 0x55d0ff9f855c, c
printf("\n");
printf("%p, %p, %c\n", &b[0], &((*b)[0]), (*b)[0]); // 0x7ffd13793718, 0x55d0ff9f855a, a
printf("%p, %p, %c\n", &b[1], &((*b)[1]), (*b)[1]); // 0x7ffd13793720, 0x55d0ff9f855b, b
printf("%p, %p, %c\n", &b[2], &((*b)[2]), (*b)[2]); // 0x7ffd13793728, 0x55d0ff9f855c, c
printf("=== func b end ===\n");
printf("=== func c start ===\n");
printf("%p, %s\n", c, *c); // 0x55d101248280, aaa
printf("%p, %s\n", c+1, *(c+1)); // 0x55d101248288, bbb
printf("%p, %s\n", c+2, *(c+2)); // 0x55d101248290, ccc
printf("\n");
printf("%p, %s\n", &c[0], c[0]); // 0x55d101248280, aaa
printf("%p, %s\n", &c[1], c[1]); // 0x55d101248288, bbb
printf("%p, %s\n", &c[2], c[2]); // 0x55d101248290, ccc
printf("=== func c end ===\n");
}
int main(int argc, char **argv) {
char*data="abcdefg";
char **c = calloc(32, 1);
c[0] = "aaa";
c[1] = "bbb";
c[2] = "ccc";

printf("%p, %c\n",data,*data); // 0x55d0ff9f855a, a
printf("%p, %c\n",data+1,*(data+1)); // 0x55d0ff9f855b, b
printf("%p, %c\n",data+2,*(data+2)); // 0x55d0ff9f855c, c
printf("\n");
printf("%p, %c\n",&data[0],data[0]); // 0x55d0ff9f855a, a
printf("%p, %c\n",&data[1],data[1]); // 0x55d0ff9f855b, b
printf("%p, %c\n",&data[2],data[2]); // 0x55d0ff9f855c, c
printf("\n");
printf("%p\n", c); // 0x55d101248280
printf("%p, %s\n", &c[0], c[0]); // 0x55d101248280, aaa
printf("%p, %s\n", &c[1], c[1]); // 0x55d101248288, bbb
printf("%p, %s\n", &c[2], c[2]); // 0x55d101248290, ccc

func(data,&data, c);
return 0;
}

在 func 內,雖然 b 和 c 都是 char **,但是用法卻大不相同,完全看傳進來的是什麼


數字實例:

void func(int *a, int **b, int **c) {
printf("=== func a start ===\n");
printf("%p, %d\n", a, *a); // 0x55bb01445280, 1
printf("%p, %d\n", a+1, *(a+1)); // 0x55bb01445284, 2
printf("%p, %d\n", a+2, *(a+2)); // 0x55bb01445288, 3
printf("\n");
printf("%p, %d\n", &a[0], a[0]); // 0x55bb01445280, 1
printf("%p, %d\n", &a[1], a[1]); // 0x55bb01445284, 2
printf("%p, %d\n", &a[2], a[2]); // 0x55bb01445288, 3
printf("=== func a end ===\n");
printf("=== func b start ===\n");
printf("%p, %p, %d\n", b, *b, **b); // 0x7ffd10e85728, 0x55bb01445280, 1
printf("%p, %p, %d\n", b+1, (*b)+1, *((*b)+1)); // 0x7ffd10e85730, 0x55bb01445284, 2
printf("%p, %p, %d\n", b+2, (*b)+2, *((*b)+2)); // 0x7ffd10e85738, 0x55bb01445288, 3
printf("\n");
printf("%p, %p, %d\n", &b[0], &((*b)[0]), (*b)[0]); // 0x7ffd10e85728, 0x55bb01445280, 1
printf("%p, %p, %d\n", &b[1], &((*b)[1]), (*b)[1]); // 0x7ffd10e85730, 0x55bb01445284, 2
printf("%p, %p, %d\n", &b[2], &((*b)[2]), (*b)[2]); // 0x7ffd10e85738, 0x55bb01445288, 3
printf("=== func b end ===\n");
printf("=== func c start ===\n");
printf("%p, %p, %d\n", c, *c, **c); // 0x55bb014452a0, 0x7ffd10e8570c, 1
printf("%p, %p, %d\n", c+1, *(c+1), **(c+1)); // 0x55bb014452a8, 0x7ffd10e85710, 2
printf("%p, %p, %d\n", c+2, *(c+2), **(c+2)); // 0x55bb014452b0, 0x7ffd10e85714, 3
printf("\n");
printf("%p, %p, %d\n", &c[0], c[0], *c[0]); // 0x55bb014452a0, 0x7ffd10e8570c, 1
printf("%p, %p, %d\n", &c[1], c[1], *c[1]); // 0x55bb014452a8, 0x7ffd10e85710, 2
printf("%p, %p, %d\n", &c[2], c[2], *c[2]); // 0x55bb014452b0, 0x7ffd10e85714, 3
printf("=== func c end ===\n\n");
}
int main(int argc, char **argv) {
int *data = malloc(sizeof(int) * 4);
int **c = calloc(sizeof(int *), 32);
int int_a = 1, int_b = 2, int_c = 3;
*(data+0) = 1;
*(data+1) = 2;
*(data+2) = 3;
c[0] = &int_a;
c[1] = &int_b;
c[2] = &int_c;

printf("%p, %d\n", data, *data); // 0x55bb01445280, 1
printf("%p, %d\n", data+1, *(data+1)); // 0x55bb01445284, 2
printf("%p, %d\n", data+2, *(data+2)); // 0x55bb01445288, 3
printf("\n");
printf("%p, %d\n", &data[0], data[0]); // 0x55bb01445280, 1
printf("%p, %d\n", &data[1], data[1]); // 0x55bb01445284, 2
printf("%p, %d\n", &data[2], data[2]); // 0x55bb01445288, 3
printf("\n");
printf("%p, %p, %p\n", &int_a, &int_b, &int_c); // 0x7ffd10e8570c, 0x7ffd10e85710, 0x7ffd10e85714
printf("%p\n", c); // 0x55bb014452a0
printf("%p, %p, %d\n", &c[0], c[0], *c[0]); // 0x55bb014452a0, 0x7ffd10e8570c, 1
printf("%p, %p, %d\n", &c[1], c[1], *c[1]); // 0x55bb014452a8, 0x7ffd10e85710, 2
printf("%p, %p, %d\n", &c[2], c[2], *c[2]); // 0x55bb014452b0, 0x7ffd10e85714, 3

func(data, &data, c);
}

跟字串的結論一樣
在 func 內,雖然 b 和 c 都是 int **,但是用法卻大不相同,完全看傳進來的是什麼

註:
    位址型態的長度間隔是 8
    int 型態的長度間隔是 4
    char 型態的長度間隔是 1
    (傳入 struct 的做法會與傳入 int 的做法類似)




沒有留言:

張貼留言