【手撕C语言基础】结构体(2)

news2024/12/23 4:14:26
  • (꒪ꇴ꒪(꒪ꇴ꒪ ),hello我是祐言
  • 博客主页:C语言基础,Linux基础,软件配置领域博主🌍
  • 快上🚘,一起学习!
  • 送给读者的一句鸡汤🤔:
  • 集中起来的意志可以击穿顽石!
  • 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏

        在上一个博客中我们简单了解和编写了一些关于结构体的知识点和代码,那么今天呢我们来学习一下如何使用好结构体,去深入了解结构体的应用,争取在以后的工作中不会被难倒。

一、结构体中可存放类型

        首先我们来了解一下结构体到底可以存放哪些类型的数据呢,大致概括为基本数据类型自定义的数据类型,下面就来归纳一下常见数据类型。

1.基本数据类型    
  • 整型:int、short、long、char
  • 浮点型:float、double
  • 布尔型:bool
struct student {
    int age;
    float gpa;
    char name[20];
    bool isEnrolled;
};
2.指针类型
  • 指向基本数据类型的指针
  • 指向其他结构体的指针
struct student {
   int *pi;
	char *pc;
	float *pf;
	int **ppi;	//二级指针
	int (*ap)[3];	//数组指针
	struct A *ps;	//结构体指针
	int (*pfunc)(int, int);	//函数指针。 注意:结构体成员中不可以定义函数,但是可以定义函数指针

};
3.枚举类型
  • 定义一组可能的取值
enum color {
    RED,
    GREEN,
    BLUE
};

struct car {
    char brand[20];
    enum color paintColor;
};
4.数组类型
  • 存储多个相同或不同类型的元素
  • 多维数组
struct point {
    int coordinates[2];
	int array[5];
	int array2[2][5];	//二维数组
	int *pia[3];	//指针数组
	struct A sa[3];	//结构体数组
	
};
5.结构体类型
  • 嵌套结构体
struct address {
    char street[20];
    char city[20];
    char state[20];
};

struct person {
    char name[20];
    int age;
    struct address homeAddress;
};

        以上是一些常用的结构体定义的实例举例,其实除了这些结构体还可以自定义很多,留给往后继续学习掌握喔,这里就不过多介绍了,毕竟多了我也不会hhh。

二、值传递和地址传递

1.值传递(Pass by Value)      

        值传递是指将实参的值复制给形参,函数内部对形参的修改不会影响到实参本身的值。在值传递中,函数操作的是形参的副本,而不是实参本身。 特点:

        (1)形参实参是两个独立的变量,在内存中占用不同的空间。
        (2)函数对形参的修改不会影响到实参的值。
        (3)值传递适用于传递简单数据类型(如整数、浮点数、字符)或较小的结构体,可以保护实参的值不被函数修改。


2.地址传递(Pass by Address)

        地址传递是指将实参的地址(指针)传递给形参,函数内部通过指针访问实参的值。在地址传递中,函数操作的是实参的内存地址,可以直接修改实参的值。 特点:

        (1)形参实参共享同一块内存空间,指向相同的数据;
        (2) 函数对形参的修改会影响到实参的值;
        (3)地址传递适用于传递较大的结构体或数组,可以避免复制大量的数据。

例程:

#include <stdio.h>


// 描述一个学生的基本信息
struct student
{
	char name[20];
	short int age;
	int number;
};


// 值传递
void show_student(struct student stu)
{
	stu.age = 30;	// 不会影响实参的值
	printf("%s, %hd, %d\n", stu.name, stu.age, stu.number);
}

// 地址传递, 更高效
// void show_student(struct student *stu)
// {
	// stu->age = 30;	// 会影响实参的值
	// printf("%s, %hd, %d\n", stu->name, stu->age, stu->number);
// }

 
int main(int argc, char *argv[])
{
	struct student zs = {.name = "zs", .age = 22, .number = 20001};
  
	show_student(zs);	// 传递的是zs这个变量的值{.name = "zs", .age = 22, .number = 20001};
	// show_student(&zs);	// 传递的是&zs, 把zs变量的地址传递到函数
	printf("%s, %hd, %d\n", zs.name, zs.age, zs.number);
	
	return 0;
}

        选择值传递还是地址传递取决于所需的功能和效率。如果函数需要修改实参的值或者传递大量的数据,通常使用地址传递;如果函数仅需要读取实参的值或者传递简单的数据类型,可以使用值传递。

三、结构体访问

1.结构体数组之间不能直接进行赋值操作

        话不多说直接上代码:

#include <stdio.h>

struct arr
{
	int array[3];
};

void show_array(int *array, int n)
{
	for (int i=0; i<n; i++)
	{
		printf("%d  ", array[i]);
	}
	printf("\n");
}

 
int main(int argc, char *argv[])
{
 // 错误的写法,被注释的   
	// int a[3] = {1, 2, 3};
	// int b[3];   
	// b = a;	// 错误
	

//正确的写法如下:
	struct arr a;
	a.array[0] = 1;
	a.array[1] = 2;
	a.array[2] = 3;
	
	struct arr b;
	b = a;
	
	show_array(b.array, 3);
	
	return 0;
}

        当我们尝试将结构体变量 a 赋值给结构体变量 b 时,我们会遇到编译错误。这是因为结构体数组之间是不能直接进行赋值的。即使结构体中只包含一个数组成员,也不允许整体进行赋值操作。

        如果我们想要复制一个结构体数组的值到另一个结构体数组,需要使用循环或其他方式逐个复制数组元素。

        因此在这个例子中,我们可以通过编写一个函数 show_array 来展示如何遍历并打印结构体数组中的元素。这样我们可以看到通过逐个复制数组元素的方式,将结构体数组 a 的值复制给结构体数组 b ,并成功打印出复制后的结果。

        这就不得不引出了结构体变量之间的赋值,但要满足两个条件

  1. 类型一致:被赋值的结构体变量和赋值操作的结构体变量类型必须完全相同。
  2. 同一结构体定义:被赋值的结构体变量和赋值操作的结构体变量必须是同一个结构体定义中声明的变量。

例如:

#include <stdio.h>

struct
{
	int a;
	char b;
}s1, s2;	//s1 s2是对于这个结构体访问的两个变量


struct
{
	int a;
	char b;
}s3, s4;	//s3 s4是对于这个结构体访问的两个变量


 
int main(int argc, char *argv[])
{
	s1.a = 100;
	s1.b = 'A';
	
	s2 = s1;	//类型一致,是同一个结构体定义的变量,可以赋值
	
	printf("%d, %c\n", s1.a, s1.b);
	printf("%d, %c\n", s2.a, s2.b);
	
	// s3 = s1;		类型不一致,赋值错误,是两个不同结构体定义的变量,当然也无法打印其值,就不展示了。
  
	return 0;
}
2.动态内存分配和释放

        动态内存分配和释放是在程序运行时动态地申请和释放内存空间的过程。它们允许程序在运行时根据需要动态地分配内存,提高了程序的灵活性和效率

        动态内存分配和释放的典型应用场景有:

  • 当程序需要在运行时根据具体情况动态调整内存空间的大小时,可以使用动态内存分配来满足需求。

  • 当程序需要存储动态生成的数据、临时数据或大量数据时,可以使用动态内存分配来避免静态内存空间不足的问题。

  • 当程序需要在函数之间传递数据或在函数执行结束后保持数据的有效性时,可以使用动态内存分配来分配内存并将指针传递给其他函数。

        需要注意的是,动态分配的内存需要在使用完毕后及时释放,以防止内存泄漏。如果不释放动态分配的内存,将导致内存泄漏问题,使得系统的可用内存逐渐减少,最终可能导致程序崩溃或系统变慢。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// 描述一个学生的基本信息
struct student
{
	char *name;
	short int age;
	int number;
}; 

 
int main(int argc, char *argv[])
{
	struct student s1 = {.name = "zhangsan", .age = 22, .number = 2001};
	s1.name = malloc(20);	//分配20字节的堆内存,把这块内存的基地址赋值给s1的成员name
	
	printf("%s, %hd, %d\n", s1.name, s1.age, s1.number);
  
	strcpy(s1.name, "zhangsi");
	printf("%s, %hd, %d\n", s1.name, s1.age, s1.number);
	
	// 使用完毕就及时释放
	free(s1.name);
  
	return 0;
 3.结构体内存访问

        结构体的内存布局是按照成员变量的顺序存储的,成员变量在内存中的地址是连续的。同时,我们可以使用 . -> 操作符来访问结构体变量和结构体指针的成员变量。

总结起来,结构体的内存布局和访问方式使我们可以灵活地操作和管理结构化的数据,同时结构体的嵌套特性可以更好地组织复杂的数据结构。

        代码如下,一一认真看o~

#include <stdio.h>

struct A
{
	int a;
	char c;
};

// 描述一个学生的基本信息
struct student
{
	char name[20];
	short int age;
	int number;
	struct A sa;
};

 
int main(int argc, char *argv[])
{
	struct student a = {"lisi", 22, 10001};
	
	
	printf("%lu byte\n", sizeof(a));	// 36byte
	printf("struct student address: %p\n", &a);	 //整个结构体的地址
	printf("name address: %p\n", &a.name);	 
	printf("age address: %p\n", &a.age);	 
	printf("number address: %p\n", &a.number);	 
	
	struct student *pa = &a;
	printf("%s\n", pa->name);
	printf("%hd\n", (&a)->age);
	printf("%d\n", (&a)->number);
	
	printf("struct student address: %p\n", pa);	 //整个结构体的地址
	printf("name address: %p\n", &pa->name);	 
	printf("age address: %p\n", &pa->age);	 
	printf("number address: %p\n", &pa->number);	 
	
	printf("sa address: %p\n", &a.sa);	//取sa地址
	printf("struct A 中的a address: %p\n", &a.sa.a);	//取struct A中的a的地址
	
	printf("sa address: %p\n", &a.sa);	//取sa地址
	printf("struct A 中的a address: %p\n", &(&a.sa)->a);	//取struct A中的a的地址
	
	
	return 0;
}

四、总结   

        结构体在C语言的学习中占有举足轻重的地位,今后也会常常用到,通过结构体,我们可以创建具有多个成员变量的数据结构,并灵活地使用和操作这些数据。操作的方式主要有一下这些方面:

  • 定义结构体类型:通过 struct 关键字定义结构体类型,包含多个成员变量。
  • 创建结构体变量:使用定义的结构体类型创建结构体变量。
  • 访问结构体成员:使用点操作符 . 或者 -> 访问结构体变量的成员变量。
  • 结构体赋值:可以将一个结构体变量的值赋给另一个结构体变量。
  • 结构体数组:可以创建结构体类型的数组来存储多个结构体变量。
  • 结构体指针:可以使用指针来引用和操作结构体变量。

        上述没写到的知识点详见另一个博客,本篇主要是一些用法与心得。

【手撕C语言基础】结构体_祐言的博客-CSDN博客

📢写在最后

  • 今天的分享就到这啦~
  • 觉得博主写的还不错的烦劳 一键三连喔~
  • 🎉感谢关注🎉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/751441.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务-Nacos环境安装

文章目录 1. 微服务1.1 微服务概括 2. 微服务框架2.1 Spring Cloud2.2 Spring Cloud alibaba/Spring Cloud Netflix2.3微服务框架组件(alibaba) 3 Nacos3.1 Nacos介绍3.3 Naocs工作结构3.3 Nacos功能3.4 环境准备下载安装 1. 微服务 1.1 微服务概括 单体架构有问题,所以做项目…

【uniapp开发小程序】设置开屏广告,广告图片全屏、覆盖自带胶囊导航

效果图&#xff1a; 点击跳转其他小程序&#xff1a; uni.navigateToMiniProgram() 官方文档&#xff1a;uni.navigateToMiniProgram(OBJECT) | uni-app官网 // 示例代码 uni.navigateToMiniProgram({appId: ,path: pages/index/index?id123,extraData: {data1: test},succes…

最新AI换脸替换工具离线版,一张图实现视频或者图片换脸

最新AI换脸替换工具离线版&#xff0c;一张图实现视频或者图片换脸 AI换脸替换工具离线版 基于开源项目&#xff0c;做了如下的小工具&#xff0c;给定一张人脸图&#xff0c;即可实现将某视频或者图片的人脸替换成给定的人脸。 软件操作依然很简单&#xff0c;鼠标悬停问号都…

七大排序算法——冒泡排序,通俗易懂的思路讲解与图解(完整Java代码)

文章目录 一、排序的概念排序的概念排序的稳定性七大排序算法 二、冒泡排序核心思想代码实现 三、性能分析四、七大排序算法 一、排序的概念 排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或…

Nacos注册与配置中心:使用详讲

文章目录 注册1. 引入依赖2. yaml配置设置命名空间注册信息在nacos中的内存状态总结nacos的服务注册发现机制 配置中心应用场景配置中心运行结构远程配置:1. 在本地进程添加config 依赖 和bootstrap依赖2. 需要引入一个bootstrap.yaml文件 案例练习 注册 所有组件配置步骤-大三…

面向Web开发人员的Linux实用入门(转)

从 web 开发的视角说一下在使用 Linux 时遇到的问题&#xff0c;主要是针对操作本身&#xff0c;因为指令在网上都可以查到&#xff0c;不会深入原理&#xff0c;但尽量实用。 基础认知 为什么使用 Linux 最初我使用 Linux 是因为我需要的应用在教程里只提供了 Linux 版本&a…

一、Dell服务器的iDRAC管理卡连接

Dell服务器的iDRAC管理卡图文教程 1、网线连接idrac口2、查看idrac地址3、匹配IP地址4、web登录idrac页面5、登录成功页面 带有集成戴尔远程访问控制器 &#xff08;idrac&#xff09;的系统具有默认用户名和密码&#xff0c;但您也可以使用安全密码对其进行配置。默认使用web浏…

【设计模式】简易俄罗斯转盘实现JAVA

大家好哇&#xff0c;我是梦辛工作室的灵&#xff0c;最近有些无聊&#xff0c;没得什么事情做&#xff0c;所以想再熟悉熟悉设计模式吧&#xff0c;然后就写了个俄罗斯转盘玩&#xff0c;还是老样子先看结果&#xff1a; 看上去还是不错的吧&#xff0c;最后那个只是打印&…

数学建模 插值算法

有问题 牛顿差值也有问题它们都有龙格现象&#xff0c;一般用分段插值。 插值预测要比灰色关联预测更加准确&#xff0c;灰色预测只有2次 拟合样本点要非常多&#xff0c;样本点少差值合适

Qt 桌面系统设计

文章目录 前言一、项目介绍二、界面布局三、按键图标四、桌面背景五、实现led功能总结 前言 这篇文章介绍 一个Qt 桌面系统的项目&#xff0c;大家可以在此基础上加以改进&#xff0c;实现更多的功能。 一、项目介绍 可以看到 这个桌面系统上分为两部分&#xff0c;左边是 三个…

在Linux上 USRP RIO 2944 使用 PCIe

支持的硬件 USRP-2900USRP-2901USRP-2920USRP-2921USRP-2922USRP-2930USRP-2932USRP-2940 40 MHzUSRP-2940 120 MHzUSRP-2942 40 MHzUSRP-2942 120 MHzUSRP-2943 40 MHzUSRP-2943 120 MHzUSRP-2944USRP-2945USRP-2950 40 MHzUSRP-2950 120 MHzUSRP-2952 40 MHzUSRP-2952 120 MH…

【Unity面试篇】Unity 面试题总结甄选 |算法相关 | ❤️持续更新❤️

前言 之前整理了一篇关于Unity面试题相关的所有知识点&#xff1a;2022年Unity 面试题 |五萬字 二佰道| Unity面试题大全&#xff0c;面试题总结【全网最全&#xff0c;收藏一篇足够面试】为了方便大家可以重点复习某个模块&#xff0c;所以将各方面的知识点进行了拆分并更新整…

山西电力市场日前价格预测【2023-07-14】

日前价格预测 预测明日&#xff08;2023-07-14&#xff09;山西电力市场全天平均日前电价为315.29元/MWh。其中&#xff0c;最高日前价格为386.08元/MWh&#xff0c;预计出现在21: 45。最低日前电价为232.93元/MWh&#xff0c;预计出现在14: 45。 价差方向预测 1&#xff1a;实…

利用windows恶意软件获取windows主机shell

实验目的&#xff1a; 模拟黑客利用windows恶意软件获取windows主机shell权限的过程 熟悉操作使用的命令实验准备&#xff1a; kali 同网段的windows主机&#xff08;关闭防火墙&#xff09; msfvenom是一个Metasploit独立的有效负载生成器&#xff0c;也是msfpayload和msfenco…

【大数据之Hive】二十二、HQL语法优化之Join优化

主要控制优化使用哪种join算法。 1 Common Join Common Join是Hive中最稳定的join算法也是默认的join算法&#xff0c;其通过一个MapReduce Job完成一个join操作。Map端负责读取join操作所需表的数据&#xff0c;并按照关联字段进行分区&#xff0c;通过Shuffle&#xff0c;将…

【动手学深度学习】--01.线性回归

文章目录 线性回归1.原理1.1线性模型1.2衡量预估质量——平方损失1.3训练数据1.4参数学习1.5优化算法 2.从零开始实现线性回归2.1生成数据集2.2批量读取数据集——Mini-batch思想2.3初始化模型参数2.4定义模型2.5定义损失函数2.6定义优化算法2.7训练模型 3.借助深度学习框架实现…

关于nginx学习记录(一)

系列文章目录 第一章 Nginx 学习入门——Nginx的概述及安装 系列文章目录 一、Nginx 概述 二、安装步骤 1.下载pcre安装包,并放入linux中,进行解压: 2.pcre解压完成后,进入解压后的文件,执行./configure命令 3.在当前目录执行命令:make && make install 4.由于到…

【并发编程的艺术读书笔记】创建线程的四种方式

创建线程的四种方式 继承Thread类 public class MyThread extends Thread {Overridepublic void run() {System.out.println("MyThread...run...");}public static void main(String[] args) {// 创建MyThread对象MyThread t1 new MyThread() ;MyThread t2 new M…

神经网络模型在深度学习中的作用

神经网络模型是一种模拟人脑神经元之间连接和相互作用的数学模型。它由多个神经元&#xff08;节点&#xff09;以层次结构相互连接而成&#xff0c;每个神经元通过学习权重和偏置&#xff0c;根据输入数据产生相应的输出。 在深度学习中&#xff0c;神经网络模型被广泛应用于…

基于ZYNQ阵列涡流检测系统硬件设计(一)

为实现阵列涡流检测系统总体功能&#xff0c;需研制一套多通道信号采集硬件系统&#xff0c;以搭配 软件编程实现分时激励和分时采集。基于以上要求&#xff0c;本章介绍了阵列涡流检测系统的硬 件模块设计。 3.1 阵列涡流检测系统总体设计 阵列涡流检测系统需要利用 DA …