目录
指针和指针类型
野指针
指针运算
指针和数组
指针:指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。由于通过地址能找到所需要的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
指针是个变量,用来存放内存单元的地址。
#include <stdio.h> int main() { int a = 10; int* pa = &a;//取出a的地址,将他放在pa中,称pa为指针变量 printf("%p\n%p\n", pa, &a); return 0; }
指针变量的大小:
#include <stdio.h> int main() { //在32位的机器中指针变量的大小是4byte,在64位的机器中,指针变量的大小是8byte //x86 是 32位 x64 是64位 //32位:有32跟地址线,每根地址线能产生一组数据,0/1;32跟地址线共产生了2^32不同的地址,每个地址控制一个字节,共控制4GB //同理,64位为8gb char* pa; short* pb; int* pc; long* pd; long long int* pe; float* pf; double* pg; long double* ph; printf("%d\n", sizeof(pa)); printf("%d\n", sizeof(pb)); printf("%d\n", sizeof(pc)); printf("%d\n", sizeof(pd)); printf("%d\n", sizeof(pe)); printf("%d\n", sizeof(pf)); printf("%d\n", sizeof(pg)); printf("%d\n", sizeof(ph)); return 0; }
指针的定义方式:
type + *
#include <stdio.h> int main() { char* pa = NULL;//char * 是字符类型的指针,用来存放char类型的变量的地址 short* pb = NULL;//short * 是短整型类型的指针,用来存放short类型变量的地址 int* pc = NULL;//int * 是整型类型的指针,用来存放int类型变量的地址 long* pd = NULL;//long* 是长整型类型的指针,用来存放long类型变量的地址 long long int* pe = NULL;//long long int* 是长长整型类型的指针,用来存放long long int 类型变量的地址 float* ph = NULL;//float * 是浮点类型变量的指针,用来存放float类型的变量 double* pf = NULL; long double* pg = NULL; return 0; }
指针类型的意义:
1)指针类型决定了指针在解引用时一次能访问几个字节;
2)指针类型决定了指针向前或向后走一步有多大;
1)指针类型决定了指针在解引用时一次能访问几个字节;
char*------------->1
short*------------>2
int * -------------->4
long*-------------->4
long long int*--->8
float--------------->4
double------------>8
#include <stdio.h> int main() { int a = 0x11223344; int* pa = &a; *pa = 0; return 0; }
#include <stdio.h> int main() { int a = 0x11223344; char* pa = &a; *pa = 0; return 0; }
#include <stdio.h> int main() { int a = 0x11223344; short* pa = &a; *pa = 0; return 0; }
2)指针类型决定了指针向前或向后走一步有多大;
char*------------->1
short*------------>2
int * -------------->4
long*-------------->4
long long int*--->8
float--------------->4
double------------>8
#include <stdio.h> int main() { char a = 1; short b = 2; int c = 3; long d = 4; long long int e = 5; float f = 6; double g = 7; char* pa = &a; short* pb = &b; int* pc = &c; long* pd = &d; long long* pe = &e; float* pf = &f; double* pg = &g; printf("%p\n", pa); printf("%p\n", pa + 1); printf("%p\n", pb); printf("%p\n", pb + 1); printf("%p\n", pc); printf("%p\n", pc + 1); printf("%p\n", pd); printf("%p\n", pd + 1); printf("%p\n", pe); printf("%p\n", pe + 1); printf("%p\n", pf); printf("%p\n", pf + 1); printf("%p\n", pg); printf("%p\n", pg + 1); return 0; }
#include <stdio.h> int main() { int arr[10] = { 0 }; int* p = arr; for (int i = 0; i < 10; i++) { *(p + i) = i; } int* q = &arr[9]; for (int i = 0; i < 10; i++) { printf("%d ", *(q - i)); } return 0; }
野指针
野指针:指针指向的位置是不可知的(随机的,不正确的,没有明确限制的)
野指针的成因:
1)指针未初始化
2)指针越界访问
3)指针指向的空间释放
1)指针未初始化
#include <stdio.h> int main() { int* p; *p = 20; return 0; }
2)指针越界访问
#include <stdio.h> int main() { int arr[10] = { 0 }; int* p = arr; for (int i = 0; i <= 10; i++) { *p = i; p++;//指针越界访问,数组只有10个元素,指针访问了11个 } return 0; }
3)指针指向的空间释放
一个值的用完被销毁后,任用这个值的地址来找这个值
#include <stdio.h> int* test() { int a = 10; return &a; } int main() { int* p = test(); printf("3\n"); printf("%d\n", *p); return 0; }
如何避免野指针:
1)指针初始化
2)小心指针越界
3)指针指向空间释放即使置NULL
4)避免返回局部变量的地址
5)指针使用之前检查有效性
#include <stdio.h> int main() { int a = 10; int* pa = &a; int* p = NULL;//不知道指针具体时,初始化为空指针 return 0; }
1)指针加减整数
2)指针减指针
3)指针的关系运算
1)指针加减整数
指针加减整数是跳过几个元素的地址
#include <stdio.h> int main() { int arr[10] = { 0 }; int* parr = arr; int sz = sizeof(arr) / sizeof(arr[0]); int* q = &arr[9]; for (int i = 0; i < sz; i++) { *(parr + i) = i; } for (int i = 0; i < sz; i++) { printf("%d", *(parr + i)); } printf("\n"); for (int i = 0; i < sz; i+=2) { printf("%d", *(parr +i)); } printf("\n"); for (int i = 0; i < sz; i+=3) { printf("%d", *(parr + i)); } printf("\n"); for (int i = 0; i < sz; i++) { printf("%d", *(q - i)); } printf("\n"); for (int i = 0; i < sz; i+=2) { printf("%d", *(q - i)); } printf("\n"); for (int i = 0; i < sz; i += 3) { printf("%d", *(q - i)); } printf("\n"); return 0; }
2)指针减指针
指针减指针是指俩地址之间元素的个数,指针必须为同一空间
#include <stdio.h> int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; printf("%d\n", &arr1[9] - &arr1[0]); printf("%d\n", &arr1[9] - &arr1[2]); char arr2[6] = { 'a','b','c','d','e','f' }; printf("%d\n", &arr2[6] - &arr2[0]); return 0; }
3)指针的关系运算
规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
#include <stdio.h> int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; for (int* pa = &arr1[9]; pa >= &arr1[0]; pa--) { *pa = 0;//标准不建议 } for (int* pb = &arr1[0]; pb < &arr1[10]; pb++) { printf("%d", *pb); } //标准规定,能与数组后面一个地址比大小,不能与数组前一个元素的地址比大小 return 0; }
数组名表示首元素的地址
把数组名当成一个地址存放到指针中,那么就可以用指针来访问一个数组
#include <stdio.h> int main() { int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; int sz = sizeof(a) / sizeof(a[0]); int* pa = a; for (int i = 0; i < sz; i++) { printf("&a[%d] == %p ----- pa + %d = %p\n", i, &a[i], i, pa + i); } return 0; }
可以指针来访问数组的元素
#include <stdio.h> int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* pa = arr; for (int i = 0; i < 10; i++) { printf("%d ", *(pa + i)); } return 0; }
二级指针:
二级指针用来存放一级指针的地址
#include <stdio.h> int main() { int a = 10; int* pa = &a;//pa是一级指针 int** ppa = &pa;//ppa是二级指针 int*** pppa = &ppa;//pppa是三级指针 ***pppa = 20; printf("%d", a); return 0; }
指针数组:存放指针的数组;
#include <stdio.h> int main() { int a = 10; int b = 20; int c = 30; int* pa = &a; int* pb = &b; int* pc = &c; int* arr[3] = { &a,&b,&c }; for (int i = 0; i < 3; i++) { printf("%d ", *(arr[i])); } return 0; }