C语言详解系列——指针与结构体

2023-10-26

指针是什么

1.指针是内存中一个最小的编号,也就是地址
2.平时口语中说的指针,通常指的是指针变量,用来存放内存地址的变量

在这里插入图片描述
如上图,通过&(取地址符号)取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是指针变量,我们通过解引用,可以使用指针变量中的地址所对应的空间。

指针变量的大小

我们将地址存放在指针变量当中,那么指针变量的大小是多少呢?一个小的内存单元是多大呢?首先来说,一个地址所占的空间为一个字节,他就是内存当中最小的单元。至于指针变量的大小,那就与操作系统有关,如果是32位的环境下,我们机器就会有32根地址线,那么每跟地址线在寻址的时候会产生高电平和低电平,就是1或者0,那么32跟地址线产生的地址就是:

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001

11111111 11111111 11111111 11111111

所以在32位的机器上,地址位32个0或1组成二进制序列,一个二进制位就是一个比特位,一个字节占八个比特位,所以在32位的机器上,一个指针变量的大小为4个字节,同理在64位的机器上,指针变量的大小为8个字节

指针与指针类型

我们都知道变量有不同的类型,那指针变量有没有类型呢?答案是也是有的,比如

char* pc = NULL;
int* pc = NULL;
short* pc = NULL;
long* pc = NULL;
float* pc = NULL;
double* pc = NULL;

我们可以了解到,指针的定义方式是:type + *,指针变量都是用于存储地址的,为什么还要区分类型呢,指针类型的意义在哪里?听我讲给你听!

int main()
{
	int i = 20;
	int* pi = &i;
	char* pc = &i;
	printf("pi = %p\n", pi);
	printf("pc = %p\n", pc);
	pi++;
	pc++;
	printf("pc = %p\n", pc);
	printf("pi = %p\n", pi);
}

在这里插入图片描述
我们可以由输出的结果判断,指针的类型决定了指针加减后向前走或者向后走的步伐有多大。比如char*这个类型的指针加一后,向后挪动一个字节,因为char类型占一个字节,而int*加一后向后挪动四个字节,因为int类型占四个字节。

int main()
{
	int i = 0x11223344;
	char* pa = &i;
	*pa = 0;
}

在这里插入图片描述

如图我们想将0赋给i,通过字符指针获取地址后,解引用,我们通过调试发现,我们仅仅改变了一个字节里面的值,其他值并没有变,而当我们用整形指针时

int main()
{
	int i = 0x11223344;
	int* pb = &i;
	*pb = 0;
	
}

在这里插入图片描述
四个字节里面的值都被我们改成了0,所以我们可以说指针的类型决定了,对指针解引用时有多大的权限。(能操作几个字节)

总结一下:

指针类型的作用:
1.指针的类型决定了指针向前或者向后走一步有多大(距离)。
2.指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

野指针

野指针就是指针指向的位置是不可知的,(随机的、不确定的、没有明确限制的)。
例如:
1.指针未初始化

int main()
{
   int* p;
   *p = 20;
   return 0;
}

2.指针越界访问

int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	for (i = 0; i < 11; i++)
	{
		*p++ = i;
	}
	return 0;
}

当我们的指针指向的范围超出数组arr的范围时,p就是野指针。
那我们该如何规避野指针呢?

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放,及时置NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性

例如:当我们不知道指针变量指向哪里时,我们可以初始化指针变量

int main()
{
	int* p = NULL;
}

我们可以设计一些条件来自查,指针是否为野指针

int main()
{
    int a = 10;
    int* p = &a;
	if (p != NULL)
	{
		*p = 20;
	}
}

还有其他的方法大家可以在练习中自己感受。

指针运算

指针加减整数

指针的地址加上或者减去指针类型乘整数的值。利用这样的性质我们可以使用指针遍历数组。

int main()
{
	int arr[4] = { 1,3,4,5 };
	int* p = arr;
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		printf("%d", *(p + i));
	}
	return 0;
}

指针减指针

我们可以通过指针减指针获取两个指针之间元素的个数。我们可以通过这个性质来模拟实现strlen()库函数。注意:两个指针相减的前提是:指针指向的同一块连续的空间

int my_strlen(char* arr)
{
	assert(arr);
	char* p = arr;
	while (*p != '\0')
	{
		p++;
	}
	return (p - arr);
}

int main()
{
	char arr[10] = "abcd";

	int len = my_strlen(arr);
	printf("%d", len);

	return 0;
}

在这里插入图片描述

指针的关系运算

指针与指针也可以比较大小,值得我们注意的是指针比大小的标准:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

指针与数组

int main()
{
	int arr[10] = { 0 };
	printf("arr = %p,&arr[0] = %p", arr, &arr[0]);
	return 0;
}

在这里插入图片描述
由此我们可以看出,数组名其实就是数组的首元素地址,我们可以通过指针的形式来访问数组。

int main()
{
    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    int *p = arr; //指针存放数组首元素的地址
    int sz = sizeof(arr) / sizeof(arr[0]);
    
    int i = 0;
    
    for (i = 0; i<sz; i++)
      {
         printf("%d ", *(p + i));
      }
      
    return 0; 
}

二级指针

因为指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里呢?当然是二级指针里了。

int main()
{
	int i = 0;
	int* p = &i;
	int** pp = &p;
}

i的地址存放在p中,p的地址存放在pp中,p是一级指针,pp是二级指针。
对于二级指针pp,我们**pp先通过*pp找到p,然后对p进行解引用,找到i。

指针数组

指针数组,到底是指针还是数组呢?答案是数组,存放指针的数组

int main()
{
	int a = 0;
	int b = 1;
	int c = 2;
	int* arr[3] = { &a,&b,&c };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%p  ", arr[i]);
	}
	
	return 0;
}

在这里插入图片描述
如图就是一个指针数组,里面有3个元素存放了,a b c三个变量的地址。

结构体

结构体是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

结构体的声明

例如我们描述一个学生变量

int main()
{
	struct student {
		char name[20];//姓名
		int age;//年龄
		char id[20];//学号
		char sex[5];//性别
	};//分号不能丢
}

结构体中的成员变量可以是标量、数组、指针、甚至是结构体。

结构体变量的定义和初始化

int main()
{
	struct id {
		int id;
	};

	struct student {
		char name[20];
		struct id ;
		int age;
	};

	struct id i_d = { 123 };//结构体的初始化
	struct student st1 = { "kkk",{124},18 };//结构体的嵌套初始化

}

结构体成员的访问

结构体变量访问成员

结构体变量的成员是通过点操作符(.)访问的,点操作符接受两个操作数。

int main()
{
	struct student {
		char name[20];
		int age;
	};

	struct student stu = { "kkk",18 };
	printf("%s %d", stu.name, stu.age);
}

在这里插入图片描述

结构体指针访问指向变量的成员
有时候我们得到的不是一个结构体变量,而是一个结构体指针,我们使用(->)访问成员。

struct student {
	char name[20];
	int age;
};
void print(struct student* pstu)
{
	printf("%s %d \n", pstu -> name, pstu -> age);
	printf("%s %d \n",(*pstu).name, (*pstu).age);
}

int main()
{

	struct student stu = { "kkk",18 };
	print(&stu);//结构体地址传参
}

结构体传参

结构体传参可以传结构体,也可以传地址

struct student {
	char name[20];
	int age;
};
void print1(struct student* pstu)
{
	printf("%s %d \n", pstu->name, pstu->age);
	printf("%s %d \n", (*pstu).name, (*pstu).age);
}

void print2(struct student stu)
{
	printf("%s %d \n", stu.name, stu.age);
}

int main()
{

	struct student stu = { "kkk",18 };
	print1(&stu);//结构体地址传参
	print2(stu);//传结构体

	return 0;
}

那么print1print2函数哪个更好一点呢?我们选择传地址,因为函数传参时,参数需要压栈。如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能下降。所以结构体传参时,要传结构体的地址。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言详解系列——指针与结构体 的相关文章

随机推荐

  • chatGPT之100个例子-从体验到精通

    简介 本博文演示了100个chatGPT在各行各业的使用例子 全部看完有助于培养chatGPT解决问题的思维 在人工智能时代 智能软件并不会淘汰人类 淘汰人类的是会使用人工智能的人 我们直接使用openAI官方chatGPT 生动演示了ch
  • web服务器的基础协议是什么,web基础概念

    1 转发和重定向的区别 实际发生位置不同 地址栏不同 转发是发生在服务器的 转发是由服务器进行跳转的 细心的朋友会发现 在转发的时候 浏览器的地址栏是没有发生变化的 在我访问Servlet111的时候 即使跳转到了Servlet222的页面
  • mysql 多字段排序

    order by 字段1 字段2 指字段1 字段2都是升序 且 先升序字段1 再升序字段2 order by字段1 字段2 desc 指字段1升序 字段2降序 order by 字段1 desc 字段2 desc 指字段1降序 字段2降序
  • 嵌入式Linux开发板_WIFI无线网卡驱动移植

    linux开发时候 无线是一个重要的部分 下面分享一下WiFi相关开发使用 本文所用开发板 tiny4412 当然也可以在jz2440上实现 嵌入式中设备想要联网 无非就 有线和无线 两种方式 有线就插上网线 没什么好说的 无线的话一种是将
  • 第2讲 KMD ISP子系统缩略词及目录结构

    QCOM Camera子系统缩略词介绍 CPAS Camera Peripherals and Support CDM Camera Data Mover TFE Thin Front End IFE Image Front End OPE
  • python词云mask需要的图_Python词云wordcloud——根据词语生成图像

    wordcloud作者github应用实例 https github com amueller word cloud blob master examples masked py 官网 https amueller github io wo
  • 【论文笔记】Leveraging Line-point Consistence to Preserve Structures for Wide Parallax Image Stitching

    论文链接 https openaccess thecvf com content CVPR2021 papers Jia Leveraging Line Point Consistence To Preserve Structures fo
  • 初步认识Spring和Mybatis

    Spring 概述 Spring是一个开源框架 是一个IOC DI 和AOP容器框架 可以让简单的JavaBean实现EJB才有的功能 EJB EJB是Enterprise Java Beans技术的简称 又被称为企业Java Beans
  • 码匠编程:7 个令人兴奋的 JavaScript 新特性

    前言 一个ECMAScript标准的制作过程 包含了Stage 0到Stage 4五个阶段 每个阶段提交至下一阶段都需要TC39审批通过 本文介绍这些新特性处于Stage 3或者Stage 4阶段 这意味着应该很快在浏览器和其他引擎中支持这
  • 【代码】将任意形状的图片裁剪成一个带圆环的头像(附效果图)

    原图 转换后 void viewDidLoad super viewDidLoad 创建一个按钮 UIButton btn UIButton alloc initWithFrame CGRectMake self view frame si
  • Window下添加telnet及端口开放

    Window下添加telnet及端口开放 一 添加telnet 其实windows上有自带的telnet工具的 只是没有安装添加进来而已 打开控制面板 选择程序与功能进去 进到程序与功能界面 点击打开或者关闭windows功能进去 弹出wi
  • 《嵌入式C语言》-第二章 C语言数据的操作

    目录 5 C语言字符集 5 1 C语言字符集是ASCII字符集的子集 5 2 C语言的字符集构成C语言的基本元素 标识符 运算符 5 3 数据类型的分类 6常量与变量 6 1 常量 6 2 变量 7 C语言运算符 7 1算术运算符 7 2赋
  • 此URL不支持Http方法POST/GET描述 请求行中接收的方法由源服务器知道,但目标资源不支持

    出现这个错误 一般是你需要在自己的sevlet里面没有实现doget dopost 方法 而 如果你实现了doget 和dopost 方法 可以从前端获取数据 设置了响应页面 但是却没有响应 就比如说 我输入表单信息之后 根据账号密码 经过
  • ASCII最小位置索引

    注意 答案仅作为参考 实际考试中下列代码通过用例100 但不代表最优解 输入一个由N个大小写字母组成的字符串 按照ASCII码值从小到大进行排序 查找字符串中第K个最小ASCII码值的字母 k gt 1 输出该字母所在字符串中的位置索引 字
  • 【Flink入门(6)】Flink的状态管理(基础)

    时间 2022 06 08 周三 题目 Flink入门 6 Flink的状态管理 基础 本专栏是尚硅谷Flink课程的笔记与思维导图 目录 引言 一 状态 state 概述 二 算子状态 Operator State 2 1 概述 2 2
  • realsense中IMU的简单使用与学习

    IMU的基本原理 如有错误 望批评指正 惯性测量单元 IMU 通常包含加速度计和陀螺仪组成的组合单元 陀螺仪就是内部有一个陀螺 它的轴由于陀螺效应始终与初始方向平行 这样就可以通过与初始方向的偏差计算出旋转方向和角度 这些都是角度变化值 而
  • HashMap底层实现原理

    HashMap HashMap 最早出现在 JDK 1 2中 底层基于散列算法实现 它是一个key value结构的容器 是一个key value的映射容器 key不重复 jdk8中的HashMap基于数组 链表 红黑树实现 不保证键值的顺
  • 树莓派内核编译和下载[1] --代码下载和交叉编译链安装

    版本信息 2022 04 04 raspios bullseye armhf full img 硬件信息 树莓派3B 整个编译和烧录已经完成 陆续更新一部分内容上来 目前网上内容不老旧不合理 所以这里重新更新出来 风险提示 首先 有服务器尽
  • java通用二维码生成工具封装

    该工具类使用google zxing实现二维码生成 可生成通用二维码和带中心图标的二维码 import java awt BasicStroke import java awt Color import java awt Graphics2
  • C语言详解系列——指针与结构体

    文章目录 指针是什么 指针变量的大小 指针与指针类型 野指针 指针运算 指针加减整数 指针减指针 指针的关系运算 指针与数组 二级指针 指针数组 结构体 结构体的声明 结构体变量的定义和初始化 结构体成员的访问 结构体传参 指针是什么 1