当前位置: 首页 > news >正文

【C语言基础】Chap. 4. 初识指针和结构体

1. 指针

了解指针前,首先要明确内存的定义:内存是电脑上重要的存储器,计算机中所有程序的运行都是在内存中进行的。

所以为了有效地使用内存,大多数现代计算机都把内存分割成一个个小的内存单元

而为了能够有效地访问到内存的每个单元,计算机又给内存单元进行了编号,以与其他内存单元进行区分,这些编号就被称为该内存单元的地址(address)。

此时就引出两个问题:

  1. 内存是怎么编号的?

 答:计算机的32位和64位实际上指的是该计算机地址线的根数,它们的通电与否分别代表1和0,这就是把电信号转换成数字信息——二进制序列。以32位为例,其能够产生的如总共有2的32次方个的序列,就可以作为内存单元的编号(地址)。如下:

 
00000000000000000000000000000000
...
00000000000000001111111111111111
...
11111111111111111111111111111111
2.一个内存单元是多大空间?

 答:每个内存单元的大小是1个字节,即8个比特。

在C语言中添加数据(如变量)时,会给对象分配空间(内存单元),而想要访问这个对象的地址,就需要利用取地址运算符&获取其地址——第一个字节的地址。示例:

 

int a = 10; //a在内存中要分配空间,int类型为4个字节
printf("%p\n", &a); //%p 是专门用来打印地址的
int* pa = &a; 

这段代码中的变量pa是用来存放地址的,在C语言中被称为指针变量(pointer variable),也可以叫指针(pointer)。

(但指针实际上是一个抽象概念,大部分情况下既可以指指针变量,也可以指地址,如果一时无法理解,最好在使用中逐渐领会,而不要强行下定义。)

对于这个指针变量,我们会说:pa“指向”a

声明它时int后的*说明其是指针变量,而int说明pa指向的对象是int类型的。

指针变量的声明可以和其他变量一起进行:

int a, b, arr[5], * p;

并且,指针是可以传递的,将上面的pa的值赋给另一个指针变量,它们将同时指向a

int* pb;
pb = pa;

获取地址后就能够通过解引用操作符*,来访问地址,对该对象进行操作:

int a = 10;
int* pa = &a;
*pa = 20; //*pa就是通过存储在pa里面的地址找到a
printf("%d\n", a); //20

因为pa指向a,所以也可以说*paa别名

*pa不仅值与a相同,实际上本质也相同。对*pa的改变也会产生对a的改变。

其实倒不如说,改变*pa就是改变a,这一点要千万注意。

而指针变量本身的大小是多少呢?

printf("%d\n", sizeof(char*)); //4 或 8
printf("%d\n", sizeof(short*)); //4 或 8
printf("%d\n", sizeof(int*)); //4 或 8
printf("%d\n", sizeof(long*)); //4 或 8
printf("%d\n", sizeof(long long*)); //4 或 8
printf("%d\n", sizeof(float*)); //4 或 8
printf("%d\n", sizeof(double*)); //4 或 8

 

实际上,指针的大小是相同的,因为指针是用来存放地址的,指针需要多大空间,取决于地址的存储需要多大空间——即4或8取决于是32位平台还是64位平台。

2. 结构体

结构体(Struct)也叫结构,是C语言的重要知识点,它使得C语言有能力描述复杂类型

如果有学过JavaScript或其他某些语言,会发现结构体与对象、记录等的概念十分相似,它是可能具有不同类型的值的集合,这些值被称为结构体的成员

当我们需要存储一组相关数据项,而且这些数据的类型不完全相同时,结构体是理想的选择。

简单示例:

//模拟一个学生的简单结构体,Stu是student的缩写
struct Stu
{
    //成员变量
    char name[20];
    int age;
    double score;
};

int main()
{
    struct Stu s = { "张三", 20, 85.5 }; //结构体的创建和初始化
    
    //读取方式1:结构体变量.成员变量
    printf("1:%s %d %lf\n", s.name, s.age, s.score);
    
    struct Stu* ps = &s; //结构体类型的指针
    
    //读取方式2:结构体指针解引用.成员变量名
    printf("2:%s %d %lf\n", (*ps).name, (*ps).age, (*ps).score);
    
    //读取方式3:结构体指针->成员变量名
    printf("3:%s %d %lf\n", ps->name, ps->age, ps->score);
    
    //以上三种读取方式的结果都是 张三 20 85.500000
    
    return 0;
}

:每个结构体代表一个新的作用域,因此在这个作用域里声明的名字都不会和程序中的其他名字冲突。C语言表述为:每个结构体都为它的成员设置了独立的命名空间(name space)。

相关文章:

  • CentOS8挂载本地ISO 配置本地YUM源
  • 手把手开发Admin 系列二(统一格式篇)
  • java计算机毕业设计物品分享网站源码+系统+数据库+lw文档+mybatis+运行部署
  • 基于MQ的分布式事务实现方案
  • 基于PaddleOCR开发easy click文字识别插件
  • 建立对象模型— 如何确定类与对象?
  • VMware Workstation Pro16 的下载与安装
  • java计算机毕业设计基于安卓Android的电子废弃物回收利用APP
  • PostgreSQL LISTEN 与NOTIFY命令
  • 基于ssm的养老智慧服务平台毕业设计源码071526
  • MySQL 安装详细步骤
  • 关于 SAP ABAP CL_HTTP_CLIENT API 中的 SSL_ID 参数
  • JavaFX、贷款服务器
  • Powershell历史执行记录
  • elementui中表格组件的高度修改没效果
  • [nginx文档翻译系列] 控制nginx
  • android 一些 utils
  • angular组件开发
  • CSS相对定位
  • docker-consul
  • Druid 在有赞的实践
  • JavaScript 基本功--面试宝典
  • js面向对象
  • js正则,这点儿就够用了
  • QQ浏览器x5内核的兼容性问题
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • 百度地图API标注+时间轴组件
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 如何实现 font-size 的响应式
  • 时间复杂度与空间复杂度分析
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 赢得Docker挑战最佳实践
  • 你对linux中grep命令知道多少?
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • 进程与线程(三)——进程/线程间通信
  • 京东物流联手山西图灵打造智能供应链,让阅读更有趣 ...
  • ​linux启动进程的方式
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • #Linux(Source Insight安装及工程建立)
  • (1)bark-ml
  • (13)Hive调优——动态分区导致的小文件问题
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (七)理解angular中的module和injector,即依赖注入
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • .bat批处理(一):@echo off
  • .Net Web项目创建比较不错的参考文章
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .net生成的类,跨工程调用显示注释