C语言总结(三)

C语言总结(三)

二级指针

二级指针也是指针变量,指针都是存储地址的变量,而二级指针是存储所指向的一级指针变量的地址,通过二级指针的解引用可以得到一级指针变量。
二级指针作为函数参数
作用:在函数外部顶一个指针p,在函数内给指针赋值,函数结束后对指针p神效,那么我们就需要二级指针。
**pt1(0x003)————>*pt2(0x002)————>p(0x001)
0x002——————–0x001———————–12
编译器总是要为函数的每个参数制作临时副本,在使用一级指针作为参数,进入函数前编译器会给指针参数创建临时副本,该副本和外部指针参数存储的内容是一样的,但是不是同一块内存地址,如果在函数内部修改指针参数的内容,修改的只是副本的内容,而不会影响外部指针参数的内容,所以如果想在调用函数修改外部指针参数的值,需要参入外部指针的地址。这时就需要使用到二级指针。

位运算

可以使用C语言对变量中的个别位进行位操作。C提供逻辑运算符和移位运算符。
按位取反~

unsigned char a = 2;//00000010
unsigned char n = ~a;//11111101

按位与&

(10010011)&(00111101) = (00010001)

按位或|

(10010011)|(00111101) = (10111111)

按位异或^

(10010011)^(00111101) = (10101110)

转置位
转置一个位表示如果该位打开,则关闭该位;如果该位关闭,则打开该位

flag^0xff  = (10010011)^(11111111) = (01101100);

不使用临时变量交换两个数

 a = a ^ b; 
 b = a ^ b;
 a = a ^ b;

分析下a和b发生交换的原因:一个整数异或本身为0,任意一个整数异或0为本身。
根据以上代码不难得出以下表达式:

1.b=(a^b)^b=a^b^b=a
2.a=(a^b)^[(a^b)^b]=a^b^[a^b^b]=a^b^a^b^b=a^a^b^b^b=b

根据前面说的前置知识,不难明白a和b,为什么发生交换了。

左移 <<
左移运算符<<将其左侧操作数的值的每位向左移动,移动的位数由其右侧操作数指定。空出来的位用0填充,并且丢弃移除左侧操作数末端的位。

(10001010) << 2 = (00101000)
左移一位相当于原值*2

右移
右移运算符>>将其左侧的操作数的值每位向右移动,移动的位数由其右侧的操作数指定。丢弃移出左侧操作数有段的位。对于unsigned类型,使用0填充左端空出的位,对于有符号类型,结果依赖于机器。空出的位可能用0填充,或者使用符号(最左端)位的副本填充。

多位数组

一维数组
数组是相同类型的变量的有序集合,在内存空间中为一大片连续的内存空间。
数组名的值是一个指针常量,也就是数组第一个元素的地址,它的类型取决于数组元素的类型
指针和数组名不是等价的,数组名在表达式中使用的时候,编译器才会产生一个指针常量。

  • 当数组名作为sizeof操作符的操作数的时候,此时sizeof返回的是整个数组的长度,而不是指针数组指针的长度。
  • 当数组名作为&操作符的操作数的时候,此时返回的是一个指向数组的指针,而不是指向某个数组元素的指针常量。

作为函数参数的数组名
编译器接受数组形式的函数形参,此时函数的形参实际上是一个指针,指向数组第一个元素的指针。
数组指针:指向数组的指针 char num[] = “abcd”; char *p = num;
指针数组:数组元素为指针的数组 char *num = {“aaa”, “bbb”, “ccc”, “ddd”};
多维数组
多维数组数组名,一维数组数组名的值是一个指针常量,是指向数组的第一个元素的指针,多维数组的数组名也是指向第一个元素,只不过第一个元素的是一个数组。

结构体

C语言允许用户自己指定这一种数据结构,它由不同的类型的数据组合成一个整体,以便引用,这些组合在一个整体中的数据是相互联系的,这样的数据结构称为结构体。
声明一个结构体类型的一般类型如下:
struct 结构体名
{成员列表}
结构体名,用作结构体类型的标志,它又称为结构体标记,大括号内是该结构体的各个成员,由它们组成一个结构体,对各成员都应进行类型声明
定义结构体类型时不要直接给成员赋值,结构体只是一个类型,编译器还没有为其分配空间,只是根据其类型定义变量时,才分配空间,有空间后才能赋值。
在涉及到结构体拷贝的时候,会出现深拷贝和浅拷贝的问题,浅拷贝只是将结构体指针指向同一片地址空间,而深拷贝才是真正的拷贝了一份保存在另一份自己的地址空间里面。在进行深拷贝的时候需要进行地址空间的开辟。
结构体的成员的偏移量,结构的成员定义下来了,则结构体的成员变量的内存布局就定下来了
在结构体成员变量中存在着内存字节对齐的问题
内存对齐原因
内存的最小单位是一个字节,当cpu从内存读取数据的时候,是一个个字节读取,但是实际上cpu将内存当成多个块,每次从内存读取一个块,这个块大小可能是2、4、8、16等。这样是为了提高内存访问效率
对于标准数据类型,它的地址只要是它的长度的整数倍
对于非标准数据类型,比如结构体,要遵循对齐原则:

  • 数组成员对齐规则,第一个数组成员应该放在offset为0的地方,以后每个数组成员应该放在offset为min(当前成员的大小,#pargama pack(n))整数倍的地方开始(比如int在32为机器上为4字节,#pargama pack(2),那么从2的倍数地方开始存储)。
  • 结构体的大小,也就是sizeof的结果,必须是min(结构体内部最大成员,#pargama pack(n))的整数倍,不足要补齐。
  • 结构体作为成员的对齐规则,如果一个结构体里面嵌套一个结构体,还是可以以最大成员类型的大小进行对齐,但是结构体A的起点为A内部最大成员的整数倍的地方。

手动设置对齐模数

  • #pragma pack(show)
    显示当前packing alignment的字节数,以warning message的形式被显示。
  • #pragma pack(push)
    将当前指定的packing alignment数组进行压栈操作,这里的栈是the insternal compiler stack,同时设置当前的packing aligment为n;如果n没有指定,则将当前的packing alinment数组压栈
  • #pragma pack(pop)
    从internal compiler stack中删除最顶端的record;如果没有指定n,则当前的栈顶record即为新的packing alignement数值;如果指定了n,则n成为新的packing alignment值
  • #pragma pack(n)
    指定packing 的数值,以字节为单位,缺省数值为8,合法数值为1,2,4,8,16.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值