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\n", sizeof(p)); printf("&p = %p, p = %p\n", &p, p); printf("&a = %p, a = %d\n", &a, a); printf("====================\n"); // * 是一个运算符. 称解引用运算符 / 间接访问运算符 *p = 16; printf("a = %d, *p = %d\n", a, *p); printf("--------------------\n"); // [] 是一个运算符. 按索引解引用 / 按索引间接访问. p[0] = 32; printf("a = %d, *p = %d\n", 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\n", 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\n", p); *p = 345; printf("*p = %d\n", *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('\n'); } 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('\n'); } 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\n", max(a, 10)); printf("min: %d\n", min(a, 10)); printf("move left 3:\n"); move_left(a, 10, 3); print_a(a, 10); printf("move right 3:\n"); move_right(a, 10, 3); print_a(a, 10); printf("reverse:\n"); reverse(a, 10); print_a(a, 10); printf("sort:\n"); 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\n", p, pch, &a); // 指针指向的类型决定了其 + 1, 地址 + 多少字节. printf("p + 1 = %p, pch + 1 = %p\n", p + 1, pch + 1); // 同时, 指针指向的类型决定了 *p 从指针指向的地址取出多少(字节)内容. printf("*p = %#x\n", *p); // 打印时, 隐式类型转换, 符号扩展 printf("*pch = %#x\n", *pch); printf("*pch + 1 = %#x\n", *(pch + 1)); printf("*pch + 2 = %#x\n", *(pch + 2)); printf("*pch + 3 = %#x\n", *(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\n", p, pv, &a); // void * 类型指针 + 1, 地址 + 1(字节). printf("p + 1 = %p, pv + 1 = %p\n", p + 1, pv + 1); printf("------------------\n"); printf("a = %#x, *p = %#x\n", a, *p); // void * 类型不允许解引用. printf("a = %#x, *pv = %#x\n", 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\n", a, b); swap1(a, b); printf("---after swap1---\n"); printf("a = %d, b = %d\n", a, b); swap2(&a, &b); printf("---after swap2---\n"); printf("a = %d, b = %d\n", 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\n", str); str[2] = 'I'; printf("str = %s\n", str); printf("----------------------------\n"); printf("s = %s\n", s); // 段错误.(试图修改只读数据段的数据) s[2] = 'I'; printf("s = %s\n", 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\n", s[6]); printf("-----------------\n"); printf("\"012345ABCDEF\"[6] = %c\n", "012345ABCDEF"[6]); printf("*(\"012345ABCDEF\" + 6) = %c\n", *("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) != '\0') i++; return i; } int my_strlen_recur(char *s) { if (*s == '\0') return 0; return 1 + my_strlen_recur(++s); } char *my_strcpy(char *dst, const char *src) { char *dst_old = dst; while ((*dst++ = *src++) != '\0') ; return dst_old; } char *my_strcat(char *dst, const char *src) { char *dst_old = dst; /* * dst --> '\0'后一字符 * while (*dst++ != '\0') * ; */ // dst --> '\0' while (*dst != '\0') dst++; while ((*dst++ = *src++) != '\0') ; return dst_old; } int my_strcmp(const char *s1, const char *s2) { while (*s1 == *s2 && *s1 != '\0') s1++, s2++; return *s1 - *s2; } char *my_strchr(const char *s, int c) { while (*s != '\0') { if (*s == c) return (char *)s; s++; } return NULL; } char *my_strstr(const char *s, const char *substr) { const char *start_cmp = NULL, *substr_start = substr; while (*s != '\0') { start_cmp = s, substr = substr_start; while (*s == *substr && *s != '\0') s++, substr++; if (*substr == '\0') return (char *)start_cmp; s = start_cmp; s++; } return NULL; } int main(void) { char s1[128]; char s2[128]; printf("test strlen, input s1:"); gets(s1); printf("len of s1 is %d\n", my_strlen(s1)); printf("test strcpy, input s1: "); gets(s1); my_strcpy(s2, s1); printf("s2: %s\n", s2); printf("test strcat, input s1: "); gets(s1); my_strcat(s2, s1); printf("s2: %s\n", s2); printf("test strcmp, input s1: "); gets(s1); printf("test strcmp, input s2: "); gets(s2); if (strcmp(s1, s2) > 0) printf("%s > %s\n", s1, s2); else if (strcmp(s1, s2) < 0) printf("%s < %s\n", s1, s2); else printf("%s == %s\n", s1, s2); int ch; char *index = NULL; printf("test strchr, input s1: "); gets(s1); printf("input ch: "); ch = getchar(); if ((index = my_strchr(s1, ch)) != NULL) printf("%s has %c, index = %d\n", s1, ch, index - s1); else printf("not find.\n"); while (getchar() != '\n') ; printf("test strstr, input s1: "); gets(s1); printf("input s2: "); gets(s2); if ((index = my_strstr(s1, s2)) != NULL) printf("%s has %s, index = %d\n", s1, s2, index - s1); else printf("not find.\n"); return 0; }
结果:
test strlen, input s1:wang len of s1 is 4 test strcpy, input s1: apk s2: apk test strcat, input s1: apk s2: apkapk test strcmp, input s1: what test strcmp, input s2: whaa what > whaa test strchr, input s1: what input ch: a what has a, index = 2 test strstr, input s1: what2222at input s2: at what2222at has at, index = 2