1,指针的基本用法1
#include <stdio.h> // 指针和数组都是复合类型, 他们从基本类型 // 或者自定义类型派生. int main(void) { // 当定义指针变量p 时, int * --> 这里的 * // 不是运算符, 而是 类型定义说明符. // 定义了一个变量p // p 是 int * 类型. p 指向 int 类型. int *p = NULL; int a = 8; // 此时, p 指向 a p = &a; printf("sizeof p = %u ", sizeof(p)); printf("&p = %p, p = %p ", &p, p); printf("&a = %p, a = %d ", &a, a); printf("==================== "); // * 是一个运算符. 称解引用运算符 / 间接访问运算符 *p = 16; printf("a = %d, *p = %d ", a, *p); printf("-------------------- "); // [] 是一个运算符. 按索引解引用 / 按索引间接访问. p[0] = 32; printf("a = %d, *p = %d ", a, *p); return 0; }
结果:
will@will-Inspiron-N4010:~/c/5th$ ./a.out sizeof p = 4 &p = 0xbf8b9f18, p = 0xbf8b9f1c &a = 0xbf8b9f1c, a = 8 ==================== a = 16, *p = 16 -------------------- a = 32, *p = 32
2,指针的基本用法2
#include <stdio.h> int main(void) { unsigned long p = 0; int a = 8; // &a 的结果是一个 int * 类型的指针值 // 将其转换为 unsigned long, 去除编译器警告 // 之后, 变量p 中存放了 变量a 的地址. p = (unsigned long)&a; // 类型决定类型之上的操作是否合法 // 所以, 将 p 强制转换为 int * 类型, // 那么对 p 进行解引用运算就合法了. *(int *)p = 16; printf("a = %d, *p = %d ", a, *(int *)p); return 0; }
结果:(int *)这个是作为定义的存在,相当于int *p
a = 16, *p = 16
3,指针基本用法3
#include <stdio.h> int main(void) { // 未初始化的指针称为野指针 // dangling pointer int *p; printf("p = %p ", p); *p = 345; printf("*p = %d ", *p); return 0; }
结果:未初始化的指针无法直接赋值。
p = 0xb77b3ff4
Segmentation fault (core dumped)
4,指针做函数参数
#include <stdio.h> void rand_a(int *p, int len) { int i; for (i = 0; i < len; i++) // *(p + i) = rand() % 100; p[i] = rand() % 100; } void print_a(int *p, int len) { int i; for (i = 0; i < len; i++) printf("%d ", *(p + i)); putchar(' '); } int main(void) { int a[10]; rand_a(a, 10); print_a(&a[0], 10); return 0; }
结果:数组传入是int a[ ],指针形式传入是int *a 都是传入数组首地址,两者可通用
will@will-Inspiron-N4010:~/c/5th$ ./a.out 83 86 77 15 93 35 86 92 49 21
5,数组和指针的通用性
#include <stdio.h> void rand_a(int *p, int len) { int i; for (i = 0; i < len; i++) *(p + i) = rand() % 100; } void print_a(int *p, int len) { int i; for (i = 0; i < len; i++) printf("%d ", *(p + i)); putchar(' '); } int max(int *p, int len) { int i; int max = *p; for (i = 0; i < len; i++) { if (*(p + i) > max) max = *(p + i); } return max; } int min(int *p, int len) { int i; int min = *p; for (i = 0; i < len; i++) { if (*(p + i) < min) min = *(p + i); } return min; } void __move_left(int *p, int len) { int i; int t = *p; for (i = 0; i < len - 1; i++) *(p + i) = *(p + i + 1); *(p + i) = t; } void move_left(int *p, int len, int shift) { int i; shift %= len; for (i = 0; i < shift; i++) __move_left(p, len); } void __move_right(int *p, int len) { int i; for (i = len - 1; i > 0; i--) { *(p + i) ^= *(p + i - 1); *(p + i - 1) ^= *(p + i); *(p + i) ^= *(p + i - 1); } } void move_right(int *p, int len, int shift) { int i; shift %= len; for (i = 0; i < shift; i++) __move_right(p, len); } void reverse(int *p, int len) { int i; for (i = 0; i < len / 2; i++) { *(p + i) ^= *(p + len - i - 1); *(p + len - i - 1) ^= *(p + i); *(p + i) ^= *(p + len - i - 1); } } void bubble_sort(int *p, int len) { int i, j; for (i = 0; i < len - 1; i++) { for (j = 0; j < len - i - 1; j++) { if (*(p + j) > *(p + j + 1)) { *(p + j) ^= *(p + j + 1); *(p + j + 1) ^= *(p + j); *(p + j) ^= *(p + j + 1); } } } } int main(void) { int a[10]; rand_a(a, 10); print_a(a, 10); printf("max: %d ", max(a, 10)); printf("min: %d ", min(a, 10)); printf("move left 3: "); move_left(a, 10, 3); print_a(a, 10); printf("move right 3: "); move_right(a, 10, 3); print_a(a, 10); printf("reverse: "); reverse(a, 10); print_a(a, 10); printf("sort: "); bubble_sort(a, 10); print_a(a, 10); return 0; }
结果和前一章节的数组变换一样。只不过是p[i] 替换成*(p+i)而已,p是首地址。
6,指针在内存中的使用
#include <stdio.h> int main(void) { int *p = NULL; char *pch = NULL; int a = 0x55667788; p = &a; pch = (char *)p; printf("p = %p, pch = %p, &a = %p ", p, pch, &a); // 指针指向的类型决定了其 + 1, 地址 + 多少字节. printf("p + 1 = %p, pch + 1 = %p ", p + 1, pch + 1); // 同时, 指针指向的类型决定了 *p 从指针指向的地址取出多少(字节)内容. printf("*p = %#x ", *p); // 打印时, 隐式类型转换, 符号扩展 printf("*pch = %#x ", *pch); printf("*pch + 1 = %#x ", *(pch + 1)); printf("*pch + 2 = %#x ", *(pch + 2)); printf("*pch + 3 = %#x ", *(pch + 3)); return 0; }
结果:
will@will-Inspiron-N4010:~/c/5th$ ./a.out p = 0xbfb39104, pch = 0xbfb39104, &a = 0xbfb39104 p + 1 = 0xbfb39108, pch + 1 = 0xbfb39105 *p = 0x55667788 *pch = 0xffffff88 *pch + 1 = 0x77 *pch + 2 = 0x66 *pch + 3 = 0x55
7,void * 指针
#include <stdio.h> int main(void) { int *p = NULL; void *pv = NULL; int a = 0x11223344; p = &a; // void * 类型和任意指针类型 类型兼容 pv = p; printf("p = %p, pv = %p, &a = %p ", p, pv, &a); // void * 类型指针 + 1, 地址 + 1(字节). printf("p + 1 = %p, pv + 1 = %p ", p + 1, pv + 1); printf("------------------ "); printf("a = %#x, *p = %#x ", a, *p); // void * 类型不允许解引用. printf("a = %#x, *pv = %#x ", a, *(int *)pv); return 0; }
结果:不允许直接使用*pv必须转换,所以就有了int *的定义。
p = 0xbfacdad4, pv = 0xbfacdad4, &a = 0xbfacdad4 p + 1 = 0xbfacdad8, pv + 1 = 0xbfacdad5 ------------------ a = 0x11223344, *p = 0x11223344 a = 0x11223344, *pv = 0x11223344
8,交换函数中指针的作用
#include <stdio.h> void swap1(int a, int b) { int t; t = a; a = b; b = t; } void swap2(int *a, int *b) { int t; t = *a; *a = *b; *b = t; } int main(void) { int a = 3, b = 5; printf("a = %d, b = %d ", a, b); swap1(a, b); printf("---after swap1--- "); printf("a = %d, b = %d ", a, b); swap2(&a, &b); printf("---after swap2--- "); printf("a = %d, b = %d ", a, b); return 0; }
结果:效果是一样的,给了地址交换。
a = 3, b = 5 ---after swap1--- a = 3, b = 5 ---after swap2--- a = 5, b = 3
9,数组和字符型指针的区别
#include <stdio.h> int main(void) { // 数组初始化, 字符存放在 str 数组中. char str[128] = "china unix"; // 将字符串的首地址给予指针变量 s // 字符串本身存放于 .rodata 段. char *s = "china unix"; printf("str = %s ", str); str[2] = 'I'; printf("str = %s ", str); printf("---------------------------- "); printf("s = %s ", s); // 段错误.(试图修改只读数据段的数据) s[2] = 'I'; printf("s = %s ", s); return 0; }
结果:数组可改,字符型指针不可更改
str = china unix str = chIna unix ---------------------------- s = china unix Segmentation fault (core dumped)
10,字符型指针应用
#include <stdio.h> int main(void) { char *s = "012345ABCDEF"; printf("s[6] = %c ", s[6]); printf("----------------- "); printf(""012345ABCDEF"[6] = %c ", "012345ABCDEF"[6]); printf("*("012345ABCDEF" + 6) = %c ", *("012345ABCDEF" + 6)); return 0; }
结果:其实效果一样
s[6] = A ----------------- "012345ABCDEF"[6] = A *("012345ABCDEF" + 6) = A
11,使用指针完成字符操作函数
#include <stdio.h> int my_strlen(char *s) { int i = 0; while (*(s + i) != '