欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > C_07_指针

C_07_指针

2024/11/30 12:26:42 来源:https://blog.csdn.net/weixin_51253120/article/details/141608848  浏览:    关键词:C_07_指针

指针

地址编号: 存的是值

指针: 存储的是地址编号值 的数据类型 是地址编号的数据类型,强调的是类型

指针变量: 数据类型为指针的变量,用于保存地址编号

地址编号

概述:

地址编号是内存每一个字节的编号统称。

​ int n = 10;

​ 在内存分配了4个字节

每个进程(运行着的程序)都有寻址范围

32位机的寻址范围时4G,0x00 00 00 00~0xff ff ff ff.

系统会为每一个字节分配一个32位的地址编号。便于系统管理内存

32位机的地址编号占4字节

64位机的地址编号占8字节

指针与指针变量

指针:是地址编号的数据类型,强调的是类型

指针变量:数据类型为指针的变量,用于保存地址编号

注意

在这里插入图片描述

指针变量定义

语法:

数据类型 * 变量名;

注意:

数据类型: 指针变量指向的地址中存储的数据 的数据类型

1,不同的指针只能存储对应的数据类型的地址

​ 如:

​ 整型的指针变量,只能存放整型变量的地址

2,如果在一行中定义多个指针变量,每个指针变量前面都需要加 * 来修饰

如:

int *p1;
char *p2;
float *p3;
double *p4;
void *p5;
...
int nums[] = {1,2,3,4,5};
int *p6 = nums;
int *p1,*p2,*p3;

指针变量的初始化

注意

1,当指针变量为局部变量,并没有为其赋初始值,此时因为是局部变量,所以系统为其赋 值为随机数,此时我们并不知道指针变量存
储的地址是什么.这种指针我们称为野指针
2,指针变量没有指向合法的地址建议初始化为NULL,这种指针我们称为空指针

int  *p  = NULL;      //空指针: 是NULL  不是0  0也有地址 而NULL 没有
int  *p;     //因为没有初始化所有初始化随机  所以就不知道指向哪里了  就是野指针

指针运算符

&

作用:取地址

int a = 10;
int *p = &a;
printf("%p\n",p);    //此时打印的是p的值即a的地址

注意:

​ 栈:静态全局区可取地址
​ 堆,常量池,代码区不可取

*

作用:取值

printf("%d\n",*p);   //将p中存储的地址中的值获取

作用**:改值**

*p =;
注意事项

野指针与空指针取值操作会出现段错误

哪怕用空指针也不用野指针 虽然空必然报错 但是错误是显性的 野指针对程序一定是坏的

因为 空指针 必报错 而野指针可能会在合法地址内也可能不在 所以 就很难排错

int  *p  = NULL;      //空指针: 是NULL  不是0  0也有地址 而NULL 没有
int  *p;     //因为没有初始化所有初始化随机  所以就不知道指向哪里了  就是野指针

指针的数据类型

int *p;
char *p;

口诀:

将指针变量名的变量名去除,剩余的就是指针变量的数据类型。

int *p  去掉变量名p   那就是 int *

指针存储的数据类型

int *p;
char *p;

口诀:

将指针变量的  变量名与最近的一个* 去除,剩余的就是指针变量存储地址对应的数据类型int *p;
去掉 *p
就是int

作用:

分析等号两边数据类型一致

二级指针

概念:

又名 指针的指针因为指针变量本质也是一个变量,在32位机中占4字节,64位机占8字节

如:

int a = 10;  //假设此时a在栈内存中的地址编号为0x00 00 00 01,长度4字节
int *p = &a; //将a的地址赋值给变量p,此时p存储的地址为a的地址即0x00 00 00 01 p本身也需要占用内存,其地址假设为 0x 00 00 00 06
int **p = &p; // 将p的地址 0x 00 00 00 06赋值给p2
1,二级指针使用  *取出的是什么?取出的是存储的一级指针本身的地址,不是一级指针存储的地址int num01=10;int num02=1;int *pl = &num01;int *p2 = &num02;*pl = 100;  //通过 * 但核心还是地址来改变值printf("num01 = %d\n",num01);    // 100  因为使用取值与改值 *将指针p存储的数据10进行了改值printf("num02 = %d\n",num02);    //  1int **p3 =&p1;   //将p1本身的地址赋值给p3 此时p3存储的是p1本身的地址*p3 = p2;        // 将 p2 的地址赋值给 p3printf("**p3  = %d\n",**p3);  // 1    **p  是* *p3 也就是取*p3地址存的值 还是num02

void与指针

void的作用:

万能指针的作用 核心作用就是作为函数的形参。

1 void 作为函数的返回值类型,表示没有返回值或返回值为NULL2 void 与指针结合称为万能指针 ,可有存储任何一种类型变量的地址。但是不能直接对 void  *p 中的p 直接取值 因为 无法确定p的取值宽度 。int num = 10;
int *p1 = #
char c = 'a';
char *p2 = &c;
void *p3 = #
void *p4 = &c;
p3 = &c;		//修改p3存储的地址

万能指针的作用:

  • 核心作用就是作为函数的形参。

万能指针的注意事项:

  • 不能直接对 void *p 中的p 直接取值 因为 无法确定p的取值宽度 。
    在这里插入图片描述

const与指针

常量指针

可以修改其存储的地址 ,无法修改

常量指针 是指针 可以修改其存储的地址,但是无法修改其存储的值。

语法:

数据类型 const *指针名称;
或者
const  数据类型 *指针名称;

示例:

#include <stdio.h>
int main(int argc, char const *argv[])
{int a = 10;int b = 1;//常量指针,本质是指针,可以修改其存储的地址,但是无法修改其存储的地址对应的值//const int *p = &a;  两种写法   写法aint const *p = &a;  //写法bp = &b;//改变p存储的地址//*p = 100;//改变p存储的地址对应的值,此处报错return 0;
}

在这里插入图片描述

指针常量

可以修改其存储的 ,无法修改存储地址

指针常量是常量 该指针存储的地址无法被修改,但是可以修改其存储的地址对应的值。

语法:

数据类型 * const 指针名称;int *  const p;    

在这里插入图片描述

常量指针常量

无法修改其存储的 ,也无法修改存储地址

概念: 常量指针指向常量

语法:

const 数据类型 * const 指针名;
或
数据类型 const * const 指针名;

示例

#include <stdio.h>
int main(int argc, char const *argv[])
{int a = 10;int b = 1;//常量指针常量//const int * const p = &a;int const * const p = &a;p = &b;//不可以改变p存储的地址*p = 100;//也不可以改变p存储的地址对应的值printf("a = %d\n",a);return 0;
}

在这里插入图片描述

数组与指针

数组名的本质

数组名 就是 数组中第一个元素的首地址

printf("arr的地址:  %p\n",arr);   // 求数组名地址
printf("arr[0]地址:%p\n",arr[0]);  //求地址首地址// 发现结果一样

数组名 就是 数组中第一个元素的首地址

在这里插入图片描述

#include <stdio.h>
int main(int argc, char const *argv[])
{// 证明数组名就是数组中第一个元素的地址int arr[] = {1, 3, 5, 7, 10};printf("arr的地址:  %p\n", arr);// 使用  (void *) 强制转换为 十六进制地址数printf("arr[0]地址:%p\n", (void *)&arr[0]);// 一维数组怎么操作  二维完全可以复刻   先定义指针赋值// 指针可以通过下标访问数组元素,这与数组名的使用方式相同:// 定义一个指向int的指针p,初始化为数组arr的首地址int *p = arr;printf("arr[1] = %d\n", arr[1]);   // 3  下标获取数组下标为1的元素printf("p[1]   = %d\n", p[1]);     // 3  指针访问数组下标为1的元素printf("*(p + 1)=%d\n", *(p + 3)); // 7   *(p+1) 等价于 p[1]printf("*P+1= %d\n", *p + 3);      //   4    这里是对*p  也就是数字取值后加1  不是位移单位printf("p[0]= %d\n", p[0]);        // 1  p[0] 等价*pprintf("数组arr的存储首地址为   %p\n", &arr);  //   0x7ffd49bad8b0printf("p的地址为:             %p\n", p);     //   0x7ffd49bad8b0printf("p[0]的地址为:          %p\n", &p[0]); //   0x7ffd49bad8b0printf(" p+1的地址为:          %p\n", p + 1); //      0x7ffd49bad8b4// 这里的+1是加步长 步长取决数组数据类型的大小  比如是int 那就是加一步长  而此时的一步长就是4字节printf("*p+1=%d\n", *p + 1); //     2   核心思想  *   取值符  就是将此地址存储的数值拿出来// *p 就是将p存储的值拿出来了  也就是1  再后移一位 所以是2printf("*(p+1)=%d\n", *(p + 1)); //  3// 将当前位置+1个步长,取的是数组下标为1的元素return 0;
}

在这里插入图片描述

事例2:

#include <stdio.h>
int main(int argc, char const *argv[])
{char str[] = "hIc";char *p = str;// 此时数组中存储的元素为char,一个char的长度为1字节,顾此时1个步长=1字节printf("%c\n", *(p + 1));printf("%c\n", *(p + 2));printf("%c\n", *(p + 3));printf("%c\n", *p + 1); //*p获取的是其地址对应的值,其地址的值为h,h+1=iprintf("%c\n", (*p) + 1);return 0;
}

指针数组与数组指针

概述

数组指针(数组的指针):指向数组,本质是指针
指针数组(存储指针的数组):本质是一个数组

示例1

#include <stdio.h>
int main(int argc, char const *argv[])
{int nums[] = {1, 2, 3};// 数组指针(数组的指针,指向数组,本质是指针)int *p = nums;int a = 1;int b = 2;int c = 3;int *p11 = &a;int *p12 = &b;int *p13 = &c;// 指针数组(存储指针的数组,本质是一个数组)int *p2[] = {p11, p12, p13};return 0;
}

示例2

#include <stdio.h>
int main(int argc, char const *argv[])
{int nums01[] = {1, 2, 3, 4, 5};int nums02[] = {11, 22, 33, 44, 55};int nums03[] = {111, 222, 333, 444, 555};// 二维数组int nums04[][5] = {{1, 2, 3, 4, 5},{11, 22, 33, 44, 55},{111, 222, 333, 444, 555}};// 指针数组int *ps[] = {nums01, nums02, nums03};printf("nums04[0][1] = %d\n", nums04[0][1]);printf("ps[0][1] = %d\n", ps[0][1]);printf("nums04[1][1]的=%d\n", nums04[1][1]);printf("(*(ps+1))[1]=%d\n", (*(ps + 1))[1]);printf("*(*(ps+1)+1)=%d\n", *(*(ps + 1) + 1));return 0;
}

示例3

#include <stdio.h>
int main(int argc, char const *argv[])
{// char strs[][50] = {"GaoLei","WangChenHui","YueZheng"};char *strs[] = {"GaoLei", "WangChenHui", "YueZheng"};printf("strs[0] = %s\n", strs[0]);       // GaoLeiprintf("strs[1] = %s\n", strs[1]);       // WangChenHuiprintf("strs[2] = %s\n", strs[2]);       // YueZhengprintf("*(strs+0) = %s\n", *(strs + 0)); //printf("*(strs+1) = %s\n", *(strs + 1));printf("*(strs+2) = %s\n", *(strs + 2));printf("(*(strs + 0))+3 = %s\n", (*(strs + 0)) + 3);printf("(*(strs + 0))[3] = %c\n", (*(strs + 0))[3]);return 0;
}

示例4

#include <stdio.h>
int main(int argc, char const *argv[])
{// char strs[][50] = {"GaoLei","WangChenHui","YueZheng"};char *strs[] = {"GaoLei", "WangChenHui", "YueZheng"};printf("strs[0]的地址=%p\n", &strs[0]);printf("strs的地址=%p\n", strs);printf("&strs的地址=%p\n", &strs);char *p;p = strs;// char **p2 = &p;// char **p2 = &strs;char **p2 = strs;printf("*p2 = %s\n", *p2);printf("**p2 = %c\n", **p2);printf("*(p2+1) = %s\n", *(p2 + 1));printf("*(p2+2) = %s\n", *(p2 + 2));printf("(*(p2+1))+4 = %s\n", (*(p2 + 1)) + 4);return 0;
}
#include <stdio.h>
int main(int argc, char const *argv[])
{char arr[] = "xxz";char *p = arr;// ASCII码值 是 97-122  也就是  小写   a-z//  大写字母的 ASCII 码值范围是 65 到 90printf("*p+1== %c\n", *p + 1); //*p得到的是 p[0] 也就是 x的ASCII 码值 120  然后加一return 0;
}

步长:

通常指的是数组中元素的内存间隔。

步长 = 数组中存储的元素的数据类型所占的字节数 当为int 那加1 就是加一步长也就是加4 当为char 一步长就是1 加1 就是加1

函数与指针

函数名的本质

函数名本质上就是函数在代码区存储的首地址

指针作为形参

函数指针

作用:记录函数的地址语法:返回值类型 (*指针名称)(指向的函数的形参列表的数据类型) = 函数名;注意:形参列表的数据类型可有可无
函数指针调用函数指针名 (实参列表);变量名 = 指针名(实参列表);

事例:

#include <stdio.h>
extern void add(int a, int b);
extern void sub(int a, int b);
extern void test(void (*p)(int, int));
int main(int argc, char const *argv[])
{printf("main函数的地址=%p\n", main);int (*p)(int, char *[]) = main;// 返回值类型 (*指针名称)(指向的函数的形参列表的数据类型) = 函数名;void (*p2)(int, int) = add;// 函数指针调用函数// 指针名(实参列表);// 变量名 = 指针名(实参列表);//  p2 = sub;p2(1, 2);test(p2);return 0;
}
void test(void (*p)(int, int))
{p(10, 12);
}
void add(int a, int b)
{printf("%d+%d=%d\n", a, b, a + b);
}
void sub(int a, int b)
{printf("%d-%d=%d\n", a, b, a - b);
}

指针作为形参

#include <stdio.h>
extern void showArray(int nums[],int len);
int main(int argc, char const *argv[])
{int nums[] = {1,2,3,4,5};showArray(nums,5);return 0;
}
void showArray(int *nums,int len)
{for (int i = 0; i < len; i++){// printf("%d\t",nums[i]);printf("%d\t",*(nums+i));}printf("\n");
}

指针作为返回值

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// extern int* getNums();
extern void getNums(int nums[],int len);
int main(int argc, char const *argv[])
{srand(time(NULL));// int *p = getNums();// for (int i = 0; i < 10; i++)// {// printf("%d\t",p[i]);// }// printf("\n");int nums[10] = {0};getNums(nums,10);
for (int i = 0; i < 10; i++)
{printf("%d\t",nums[i]);
}printf("\n");return 0;
}
// int* getNums()
// {
// static int nums[10] = {0};
// for (int i = 0; i < 10; i++)
// {
// nums[i] = rand() % 100;
// }
// return nums;
// }
void getNums(int nums[],int len)
{
for (int i = 0; i < len; i++){nums[i] = rand() % 100;}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com