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

《每天一分钟学习C语言·七》指针、字节对齐等

1、
对于二维数组如a[3][4]可以当做有三个元素的一维数组,每个元素包含四个小元素。

2、
printf(“%-5d”, i); //负号表示左对齐,5d表示空五个光标的位置

3、
栈:先进后出,堆:先进先出

4、
(1)int * p; //p是指针变量名字, int *表示p变量存放的是int类型的地址,p = &i; // 把i地址赋给了p,此时p指向i, * p为p指向的地址存放的变量,即 * p为i的整型变量的值。
(2)指针就是地址,地址就是指针,地址就是内存单元的编号
(3)指针变量就是存放地址的变量
(4)CPU可以直接操控内存条
(5)int *p; * p=3; //错误,因为指针变量p没有初始化
(6)int * p; //没有给指针变量初始化,p指向内存单元随意一个编号,这种情况下是不能读写随意编号里面存放的内容的,则输出 * p错误,比如随意指向了电脑图库的地址,如果能随意读写就侵犯隐私了。
(7)假如指针变量p,q同时指向一个地址,那free( p);表示p指向的空间被释放,不能在free(q);,因为p,q指向同一个空间,这个空间已经在free( p)的时候已被释放,如果没有被释放,那这个内存的空间就会被一直占有,会容易导致内存泄漏;
(8)int * p = (int * )malloc(4); //动态分配四个字节内存空间,返回第一个字节地址给p,即p指向第一个字节的地址。之所以强制类型转换就是告诉P指向的地址是保存整型变量的地址。系统总共分配了8个字节的空间,静态分配指针变量p占4个字节,p指向的动态分配的内存空间占4个字节,一共8个。Free( p)表示把p指向的动态分配的内存空间给释放掉,但p本身的内存不会释放,因为p内存是静态分配的,这需要等函数执行结束由系统释放。
(9)静态内存都是在栈里分配的,动态内存在堆里分配
(10)int ** p中p存放的是地址的地址,如int i = 3; int * q = &i; p = &q;
则 * p == q,又 * q == i,所以**p == i

5、
指针和数组
(1)数组名是第一个元素的地址,则p[0] == *p p[i] == *(p+i)
(2)数组是连续的
(3)a[2]; b[2]; a = b //error,数组名是指针常量,常量不可以被赋值
(4)

void f(int a[])
{int i;int j = sizeof(a);printf("%d\n", j); //长度为4/*for(i=0; i<sizeof(p)/sizeof(*p); i++)printf("%d\n", *(p+i));*/
}int main(void)
{int a[5] = {1, 2, 3, 4, 5};printf("%d\n", sizeof(a)); //长度为20f(a);getchar();return 0;
}

主函数输出长度为20,自定义函数输出长度为4,那是因为把数组名传入自定义函数就自动转化为指针的形式进行操作,而指针的长度32位系统固定为4,64位系统固定为8(注意:32位系统和64位系统中编译器为了相互兼容指针都占4个字节)
(5)如果两个指针变量指向的是同一个连续空间不同的存储单元,这两个指针可以相减,比如在数组里。
(6)一个变量的地址比如1001H地址里面存放3这个整型,这个1001H是整型的首个字节的地址,因为整型有四个字节,而指针指向的变量的地址都是首地址。
(7)动态定义一维数组

int len;
int i;
int * p;printf("输入一维数组的长度:");
scanf("%d", &len);
p = (int *)malloc(len * 4); //给p指向的空间分配len*4个字节空间,假如len = 4;//*p为前四个字节存放的整型,*(p+1)为后四个字节存放的整型,*(p+2)为后后四个字节存放的整型//*(p+3)为最后一组四个字节存放的整型
//给动态数组赋值
*p = 1;
p[1] = 2; //*(p+1) == p[1]
*(p+2) = 3;
*(p+3) = 4;for(i=0; i<4; i++)printf("%d\n", *(p+i)); //1 2 3 4
free(p);

6、
指针的一个不容易想通的问题,以后指针出问题就看这个例子

int main(void)
{int i = 2;int * p;f1(p);printf("%d\n", *p);getchar();return 0;
}void f1(int * q)
{*q = 3;
}

显示结果错误,p没有初始化,随意的指向了内存的一个空间,又把这个地址给了q,及p,q指向了一个相同的内存空间,*q修改了这个内存空间的内容是错误的,不确定的一个内存空间的内容是无法读写的。

第二种:

int main(void)
{int i = 2;int * p = &i;f1(p);printf("%d\n", *p);getchar();return 0;
}void f1(int * q)
{q = (int *)malloc(4);*q = 3;
}

输出答案是2不是3,首先p指向i的地址,则p == 2,把p地址赋给q,则p,q共同指向i地址,这时若q = 3,则i的值会变。但在函数里却给q分配了一个新的内存空间,这时q指向这个动态内存空间,跟p没关系,p依然指向i地址,这时p=3不会影响i的值,所以p依然为2

第三种:

int main(void)
{int i = 2;int * p = &i;f1(&p);printf("%d\n", *p);free(p);getchar();return 0;
}void f1(int ** q)
{*q = (int *)malloc(4);**q = 3;
}

答案为3不是2,首先把i地址赋给p,这时p指向i地址,p==2。然后把p地址的地址赋给q,这时q指向p地址的地址,q便是p地址,修改q的值便是修改p地址,这时若给q申请一个内存空间,那么q和p都指向这个内存空间,p不在指向i地址,这时给**q赋值,就是把q和p共同指向的内容空间放入值,那么*p就是这个值,用完要释放这个内存空间。

7、
结构体和联合体
struct student
{

};
struct student是一个数据类型,int ,double…也是一个数据类型。
struct student st; //定义一个struct student类型的变量st
两种赋值方式:struct student st = {50, 34.2f, ‘F’};
st.age = 20; st.score = 34.3f; st.sex = ‘F’;
第二种取值方式:struct student * pst = &st; //把st地址赋给pst,即pst指向st地址。printf(“%d\n”, pst->age); //20 pst->age = 10; //因pst指向的内存空间为st的内存空间,所以修改pst->age的值即st.age值也会变。另一个写法(*pst).age

(2)结构体占多少个字节数?
涉及到字节对齐,(需要字节对齐的根本原因在于CPU访问数据的效率问题)总的字节数必须是结构体中最大成员变量字节数的整数倍,前一个成员变量必须是后一个成员变量字节的整数倍,不足自动补齐。(注:结构体首地址是第一个成员地址)如

struct student
{int num;doube mark;char name;
}

int占四个字节,double占八个字节,所以int自动补齐四个字节一共八个字节是double整数倍,这时一共4+4+8=16个字节是char字节数的整数倍,这时总字节数为4+4+8+1=17不满足是最大成员变量double字节数的整数倍,故在自动补齐7个字节,这时一共是24个字节。sizeof(struct student) == 24

struct student
{char ch[5];short k[3];char arr[9];
}

整除是整除的数据类型。5不能被short(2)整除,故5+1
5+1+6=12可以被char(1)整除
12+9=21不能被最大数据类型short(2)整除,故21+1=22

union uni
{struct s{short a[5];};double i;char a[9];
};

注意:联合体中如果有结构体,字节对齐时会忽略结构体的存在,相当于联合体中只有double i和char a[9],或者如果结构体中有结构体,字节对齐时会忽略这个结构体的存在。
先找最大宽度字节数为9, 9不能被double(8)整除,故9+7=16
16既能被char整除又能被double整除

union uni
{char a[11];short i[3];double k[2];
};

先找最大宽度字节16,16能被char(1)整除,然后16又能被short(2)整除,能被double整除,故为16

还有一种情况:

struct st2 {double i;
};struct st1 {struct st2 st;int i;
};

printf(“%d\n”, sizeof(struct st1)); //这种情况会把嵌套的结构体字节数算进去,嵌套结构体字节数为8,则8+4+4 = 16是最大数据类型double (8)的倍数

union uni
{char a[11];short i[3];double k[2];
};struct student {union uni u;int j;
}st;

联合体字节数:16,结构体总字节数:16+4+4=24是最大数据类型double (8)的倍数

在这里插入图片描述

相关文章:

  • 只更新软件,座椅为何能获得加热功能?——一文读懂OTA
  • npm的使用技巧
  • UE5 Landscape 制作GIS卫星图地形
  • docker的应用和定义
  • [CVPR 2023:3D Gaussian Splatting:实时的神经场渲染]
  • RTP/RTCP/RTSP/SIP/SDP/RTMP对比
  • 10 Vue3中v-html指令的用法
  • 【Matlab in VSCode】在VSCode中编辑MATLAB文件
  • Win7如何修改MAC地址
  • 油猴脚本教程案例【键盘监听】-编写 ChatGPT 快捷键优化
  • 【原理图PCB专题】原理图图纸锁定/解锁与PCB文件加密方式
  • C语言操作符详解+运算符优先级表格
  • 云原生系列2-CICD持续集成部署-GitLab和Jenkins
  • Linux环境安装Hadoop
  • JDBC学习,从入门到入土
  • __proto__ 和 prototype的关系
  • canvas绘制圆角头像
  • Docker容器管理
  • eclipse(luna)创建web工程
  • es6
  • HTTP那些事
  • JavaScript设计模式与开发实践系列之策略模式
  • k8s 面向应用开发者的基础命令
  • Promise面试题2实现异步串行执行
  • vue--为什么data属性必须是一个函数
  • Webpack 4 学习01(基础配置)
  • 不发不行!Netty集成文字图片聊天室外加TCP/IP软硬件通信
  • 对话 CTO〡听神策数据 CTO 曹犟描绘数据分析行业的无限可能
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 测评:对于写作的人来说,Markdown是你最好的朋友 ...
  • #Linux(权限管理)
  • #QT(一种朴素的计算器实现方法)
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • $NOIp2018$劝退记
  • (2020)Java后端开发----(面试题和笔试题)
  • (Oracle)SQL优化技巧(一):分页查询
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (附源码)ssm高校实验室 毕业设计 800008
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • (转)负载均衡,回话保持,cookie
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .Net中间语言BeforeFieldInit
  • /proc/vmstat 详解
  • ::
  • @angular/cli项目构建--http(2)
  • @hook扩展分析
  • [20161214]如何确定dbid.txt
  • [Android]Tool-Systrace
  • [asp.net core]project.json(2)
  • [AX]AX2012 SSRS报表Drill through action
  • [EULAR文摘] 脊柱放射学持续进展是否显著影响关节功能