c—指针初识篇

    科技2022-08-04  109

    目录

    指针初识1.什么是指针2.什么是指针变量3.指针的定义4.指针如何表示数据 指针占用字节数指针的偏移运算指针操作数组多级指针万能指针内存四区

    指针初识

    1.什么是指针

    地址: 它是一个整数 如何获取地址: &,取地址运算符 #include<stdio.h> int main() { int i = 0; int j = 0; printf("%p\n", &i); printf("%p\n", &j); //%p,以整数形式输出指针 return 0; }

    这里看到,地址相近,有利于提高运行效率

    2.什么是指针变量

    存储地址的变量:指针变量 int p=&i;//整形变量存储地址,但是这样做不方便分析问题 //为了方便用指针存储地址 int *pi=&i;//指针存储地址

    3.指针的定义

    3.1 类型 *变量名; 如 int *pi; int *pi; char *pch; float *pf; float* pf;//两种定义方法都可以 3.2 指针的类型: 去掉变量名 如 int * 3.3 指针所指向的类型: 去掉变量名和* 如 int 本质:就是指针要操作的数据类型 //易错的写法 int *pp = NULL; //初始化 //pp才是指针(地址),用来存储地址 //*pp是指针变量的使用 //*pp = # //语法错误 pp=&num; //语法正确 pp存储地址

    4.指针如何表示数据

    4.1 用变量地址赋值 4.1 用: *地址,来表示数据,表示变量 5.空类型的指针: NULL ---> (void *)0; 把0强制转化成(void*)0 //void *类型 用于对指针变量初始化, 可以给任何类型的指针做初始化 int *pi=NULL; char *pch=NULL; float *pf=NULL; float *pf=(void *)0; //取指针的值 printf("%d\n", *pNum); //用"*地址" 就可以取当前地址中的值 printf("%d"\n,*(&Num)); //特殊取值法 printf("%d\n", pNum[0]); //指针与函数知识

    指针占用字节数

    //指针类型占用的字节数 //32位系统下都是4个字节 printf("%d\t%d\t%d\n", sizeof(int*), sizeof(char*), sizeof(float*)); //64位系统下是8个字节 printf("%d\t%d\t%d\n", sizeof(int*), sizeof(char*), sizeof(float*)); 6.运行时的错误,如何调试--->断点测试 7.野指针: 就没有指向的指针 (没有初始化的指针,被释放的指针没做收尾)

    指针的偏移运算

    基本运算 1.取值: *地址 2.p+n或者p-n int *p=NULL; //字节的偏移,不是数字上加减n 真正的字节数的偏移: p+n p+sizeof(指针所指向的类型)*n p-n p-sizeof(指针所指向的类型)*n 3.不同类型指针变量减操作,无实际价值 int main() { int* pInt = NULL; char* pChar = NULL; printf("%p\n", pInt); printf("%p\n", pChar); printf("%p\n", pInt + 1); printf("%p\n", pChar + 1); int(*p)[3] = NULL; //指针的类型 int(*)[3] //指针所指向类型 int[3] //int array[3] 占用12字节 printf("%p\n", p + 1); //p+sizeof(所指向的类型)*1 输出0000000C return 0; }

    指针操作数组

    指针操作数组 一维数组: 数组名: 表示整个数组占用的空间的首地址 对于int array[4]来说 array是数组名 等效于 &array[0] 两者都是整个数组的首地址

    #include <stdio.h> int main() { int array[4] = { 1,2,3,4 }; int* p = array; p = &array[0]; //与上一个语句等效 for (int i = 0; i < 4; i++) //一维指针打印一个数组 { //*(p+i) 等效p[i] 等效array[i] printf("%d\t", *(p + i)); //p+i是地址,*(p + i)是数字 //printf("%d\t", p[i]); 和上面等效 } }

    //不正常的情况的 //p[i] 等效*(p+i) p = &array[2]; //说明*p指向了array[2] printf("\n%d\n", p[1]); //p[1]此时等效于array[2+1],也等效于*(&array[2]+1) 见下图 printf("%d\n", *(&array[1] + 2));//该式操作比较麻烦,因此指针操作数组时,直接用上式的指针名替换数组的名的用法 //不用指针名替换数组的名时的情况,输入的时候用用指针 for (int i = 0; i < 3; i++) { scanf_s("%d", array + i); //array是一个地址,array + i也是一个地址,不用取地址符 }

    int array2D[2][2] = { 1,2,3,4 }; p = &array2D[0][0]; for (int i = 0; i < 4; i++) //降维打击 { printf("%d\t", p[i]); } printf("\n");

    多级指针

    #include <stdio.h> int main() { //变量地址用指针变量存储 int num = 0; int* p = &num; //指针变量的地址用二级指针存储 int** pp = &p; //两个星号 printf("%d\n", **pp); //用两个星号+2级指针名,用来获取二级指针的值 //三级指针的存储 int*** ppp = &pp; printf("%d\n", ***ppp); //类似5级指针用来存储4级指针 return 0; }

    万能指针

    万能指针: void * 类型的指针 1.万能指针可以操作任何类型指针 2.使用前必须强制类型 3.当做函数返回值,当做函数参数时使用,可以忽略数据类型进行操作

    void* mytime() //函数是void*类型时,需要强制类型转换 { return NULL; } int main() { int num = 0; void* pNum = &num; //使用的时候必须强制类型转换 printf("%d\n", *(int*)pNum); //printf("%d\n", *pNum); 此时有语法错误 char cNum = 'A'; pNum = &cNum; int* p = (void*)mytime(); //使用时需要强制类型转换 printf("%c\n", *(char*)pNum); return 0; }

    内存四区

    堆区 :动态内存申请的内存 手动申请,手动释放 栈区 : 局部变量,函数 自动释放,当使用完后系统会回收资源 栈结构: FILO,后进先出 堆: 随机访问 静态区: 全局变量+静态变量 常量区: 不能改变 代码区: 写的代码编译后存储的位置

    #include <stdio.h> //不能返回局部变量地址 //warning C4172: 返回局部变量或临时变量的地址: num int* ReturnPoint() { int num = 1001; return &num; } int* returnNum(int a) //形参存在局部变量里 { return &a; } int* returnMyNum(int *a) //不算 { return a; //返回指针变量的值 } int main() { //写入访问权限冲突 char* p = "ILoveyou"; //不会修改,只做打印显示需求,把字符串从常量区的首地址赋值给p //常量区,不能修改 //*p = "I"; 错误,写入访问权限冲突 //*p = 'I'; 错误 //printf("%d\n", *p); char str[] = "ILoveyou"; //数组去存,指针操作,可以修改 p = &str[0]; //一个是用p指向常量区,一个是用p指向数组地址 //*p相当于*(p+0) p[0] str[0] *p = 'C'; printf("%s", p); int* pReturn = ReturnPoint(); printf("\n第一次:%d\n", *pReturn); printf("第二次:%d\n", *pReturn); return 0; }
    Processed: 0.015, SQL: 8