c语言关键知识点总结

2 篇文章 0 订阅
1 篇文章 0 订阅

第一部分操作符sizeof

有个概念要说下,

指针不同于普通变量,指针存的是地址,而地址的范围只和机器字以及系统有关

在32位系统中,所有指针都是4B

在64位系统中,所有指针都是8B,普通变量仍然为4字节

下面的程序运行在64bit系统中结果:

  1 #include<stdio.h>
  2 
  3 void main(void)
  4 {
  5     int a[] = {1,2,3,4};
  6     printf("%ld\n",sizeof(int));  //4
  7     printf("%ld\n",sizeof(int *));  //8
  8     printf("%ld\n",sizeof(a));  //16  a是数组名字,代表整个数组
  9     printf("%ld\n",sizeof(a+0));  //8   数组名是和第一个元素地址一样,a+0是第二个元素的地址也是一个指针
 10     printf("%ld\n",sizeof(*a));  //4   整型变量
 11     printf("%ld\n",sizeof(a+1));  //8   同上
 12     printf("%ld\n",sizeof(a[1]));  //4  整型变量
 13     printf("%ld\n",sizeof(&a));  //8    指针地址
 14     printf("%ld\n",sizeof(*&a));  //16  代表数组a
 15     printf("%ld\n",sizeof(&a+1));  //8  是个指针
 16     printf("%ld\n",sizeof(&a[0]));  //8 是个指针
 17     printf("%ld\n",sizeof(&a[0]+1));  //8 是个指针
 18 }   
~           

以上参考32位的结果是,引用其他大神写的

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));  //16
printf("%d\n",sizeof(a+0));  //4
printf("%d\n",sizeof(*a));  //4
printf("%d\n",sizeof(a+1));  //4
printf("%d\n",sizeof(a[1]));  //4
printf("%d\n",sizeof(&a));  //4
printf("%d\n",sizeof(*&a));  //16
printf("%d\n",sizeof(&a+1));  //4
printf("%d\n",sizeof(&a[0]));  //4
printf("%d\n",sizeof(&a[0]+1));  //4
--------------------- 
作者:ty6693 
来源:CSDN 
原文:https://blog.csdn.net/ty6693/article/details/86699176 
版权声明:本文为博主原创文章,转载请附上博文链接!

另外数组名作为形参使用,将数组名当作指针处理。

第二部分数组名和数组地址

 12     int a[] = {1,2,3,4};
 13 
 14     printf("addr of a = 0x%p\n", a);
 15     printf("addr of &a = 0x%p\n", &a);
 16     printf("addr of a + 1 = 0x%p\n", a + 1);
 17     printf("addr of &a + 1 = 0x%p\n", &a + 1);
 18     printf("addr of &a[3] = 0x%p\n", &a[3]);

结果:
addr of a = 0x0x7ffc894f2b00
addr of &a = 0x0x7ffc894f2b00
addr of a + 1 = 0x0x7ffc894f2b04
addr of &a + 1 = 0x0x7ffc894f2b10
addr of &a[3] = 0x0x7ffc894f2b0c

以下内容为转载

具体地址:https://www.cnblogs.com/xiaodingmu/p/7200867.html

首先a是一个数组名,当看到这个a与&a时,一般我们的理解都是这个数组的首地址。没错,如果加上打印的话,确实两个值是一样的。

不过&a是整个数组的首地址,a则是数组首元素的地址,虽然值一样,但是意义却不相同。

 由此我们可以区分a+1和&a+1的区别了。

&a+i = a + i*sizeof(a);
a+i = a +i*sizeof(a[0]); 

第三部分字节对齐:

从网上摘了一段:

如果一个32位的数据没有存放在4字节整除的内存地址处,那么处理器就需要2个总线周期对其进行访问,显然访问效率下降很多。因此,通过合理的内存对齐可以提高访问效率。为使CPU能够对数据进行快速访问,数据的起始地址应具有“对齐”特性。比如4字节数据的起始地址应位于4字节边界上,即起始地址能够被4整除。此外,合理利用字节对齐还可以有效地节省存储空间。但要注意,在32位机中使用1字节或2字节对齐,反而会降低变量访问速度。因此需要考虑处理器类型。还应考虑编译器的类型。在VC/C++和GNU GCC中都是默认是4字节对齐。

记住2点一是默认4字节对齐二是提高访问效率。

我使用的机器为64位的,例子中所有的指针的大小均为8字节
187 struct test {
188     int num;  //4 字节
189     int pcname; //4字节
190     char a[2];  //本身2个字节,但是因为对齐 所以此元素占4字节
191     short sba[4]; //short占2字节一共8字节
192 };

结果:
size of struct test = 20


187 struct test {
188     int num;   //4字节 补4个字节  一共8字节
189     char *pcname;  //8字节 影响前后2元素的字节,补齐的字节数。
190     char a[2];   //本身2字节,因为对齐8字节补,补6个字节
191     short sba[4];//short占2字节一共8字节
192 };

结果
size of struct test = 32


187 struct test {
188     int num;  //4字节
189     char a[2]; //4字节
190     short sba[4];//8字节
191     char *pcname;//8字节
192 };  

结果
size of struct test = 24

187 struct test {
188     char num;
189     char num1;
190     char num2;
191     char num3;
195 };
size of struct test = 4

 首先,我们给出四个概念:

  1)数据类型自身的对齐值:就是基本数据类型的自身对齐值,比如char类型的自身对齐值为1字节,int类型的自身对齐值为4字节。

  2)指定对齐值:预编译命令#pragma pack (value)指定的对齐值value。

  3)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值,比如以上的struct A的对齐值为4。

  4)数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小的那个值。

 

其实,除了结构体之外,整个程序在给每个变量进行内存分配时都会遵循对齐机制,也都会产生内存空间的浪费。但我们要知道,这种浪费是值得的,因为它换来的是效率的提高。

  以上分析都是建立在程序默认的对齐值基础之上的,我们可以通过添加预定义命令#pragma pack(value)来对对齐值进行自定义,比如#pragma pack(1),对齐值变为1,此时内存紧凑,不会出现内存浪费,但效率降低了。效率之所以降低,是因为:如果存在更大字节数的变量时(比1大),比如int类型,需要进行多次读周期才能将一个int数据拼凑起来。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值