基于c语言知识点的补遗介绍

 更新时间:2013年05月23日 15:48:18   作者:  
本篇文章是对c语言知识点的一些补遗进行详细的分析介绍,需要的朋友参考下

使用C很长时间,但是很难说对c的各个点都十分的透彻。虽然c不像c++那样复杂,但是还有很多叽里旮旯儿:并不是他们有多难,而是在于他们平时用的不多,或者和人的第一直觉相悖,再或者初学时经验有限理解不深根本没有记住。
下面的这些东西可能来自《c专家编程》或者网络。最近发现基础的经典的书籍常读常新,原因可能有两个:
1、随着自己经验的增长,你的认识可能会不一样,思维的方式也会有所变化,而得到的东西自然会是新的东西。
2、早些时候经验有限,有些点可能根本就没有完全理解。现在你可以理解的更深刻。
这方面的书籍再比如《代码大全》,前几天翻了一下,又有不同的认识。
进入正题:
1、有符号和无符号的比较:
printf("%d\n", sizeof('A')):打印的值是4(或者是int的长度)而不是1。因为c有类型提升,它会首先把'A'提升为int类型,然后在传给sizeof。表达式中的参数会提升为int或者double,然后在进行运算,之后再进行裁剪,获得指定类型的值。
if (-1 <= sizeof(int)):sizeof的返回值是unsigned int,-1会被类型转换为unsignedint,然后在进行比较。。
这里涉及到的是类型提升,隐式类型转换。它会在表达式中发生,也会在函数入参中发生。
2、枚举在内存中的大小:占四个字节。
3、局部变量也是字节对齐的:
        E_T g;
        E_T f;
        E_T e = false;
        char c1;
        char c2;
        int i1;
        char c3;
        int i2;
printf("%p, %p, %p, %p, %p, %p, %p, %p\n", &g, &f, &e, &c1, &c2, &i1, &c3, &i2);



--表示是补齐的位。
4、宏定义中的#和##:#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。
而##被称为连接符(concatenator),用来将两个Token连接为一个Token。
5、浮点数不可以用等于比较。
6、void foobar2() 表示函数入参个数有多个,不确定。如果表示没有产生,应该是:void foobar2(void)
7、全局变量会被初始化为0,但是,栈中的局部变量不会被初始化。
8、inline函数和宏:内联函数是真正的函数,但是它是在编译期的优化。
9、    int a[5];    printf("%x\n", a);    printf("%x\n", a+1);    printf("%x\n", &a);    printf("%x\n", &a+1);
最后一个,&a+1,&a表示数组,所以,应该是增加数组大小:4*5个字节。
10、10U表示一个无符号类型的数字10.
11、移位运算的优先级比较低,低于四则运算。
12、左移n位,相当于乘与2的n次方。右移相当于处于2的n次方。
13、指针和数组:
1)、void fun(char buf[100])
{
printf("%d, \n", sizeof(buf));
}
打印的值是4,而不是100。
2)、在一个文件中char p[10] = "";
在另外一个文件中声明:extern char *p;
然后,在声明的文件中sizeof(p),答案是4。也就是,sizeof计算的是声明的类型。
3)对于编译器而言,一个数组就是一个地址,一个指针就是一个地址的地址。
4)所有作为函数参数的数组名编译器都会转换为指针,在其他所有的情况下,数组的声明就是数组,指针的什么就是指针。
数组和指针相同情况的规则:
1、表达式中的数组名(与声明不同)被编译器当作一个指向该数组的第一个元素的指针。
2、下标总是与指针的偏移量相同。
3、在函数的声明中,数组名被编译器当作指向该数组第一个元素的指针。这个操作时编译器完成的。原因是出于效率的考虑。因为这样就是引用传递而非值传递。值 传递需要拷贝。这也可以看的出sizeof是在汇编中操作的。
arry[-1]的行为是未定义的。
总结:
1)a[i]这样的形式对a进行访问,总是被编译器改写为像*(a+i)的形式。
2)指针始终是指针,你不可以把它改写成数组,但是可以通过数组的形式访问。
3)数组作为函数的参数,会被编译器改写成指针。
4)指针和数组的什么必须配对。
14、声明与定义:声明可以由多个,定义只有一个。定义是特殊的声明,它为对象分配了内存。而声明时普通的声明,描述其他地方创建的对象。
声明的优先级规则:
a:从他的名字开始按照优先次序依次读取:
b:优先级的高低:
1、声明中被括号括起来的那部分。
2、后缀操作符:
括号()表示是一个函数;
方括号[]表示是一个数组;
3、前缀操作符:*表示指向什么的指针;
4、const紧跟变量则修饰变量不可修改,紧跟类型则指向的东西不可修改。
15、多维数组:
a[2][3]:a是一个数组,有两个元素。每个元素又是一个数组,有三个元素。
内存布局:a[0][0],a[0][1],a[0][2],a[1][0]...地址一直变大。
多维数组,数组的数组作为函数的形参,会被转化为数组指针,数组的指针,也是行指针。本质上也是指针。
16、结构体默认的字节对齐一般满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员自身大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

相关文章

  • C++实现折半插入排序(BinaryInsertSort)

    C++实现折半插入排序(BinaryInsertSort)

    这篇文章主要为大家详细介绍了C++实现折半插入排序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • C++ 基于BFS算法的走迷宫自动寻路的实现

    C++ 基于BFS算法的走迷宫自动寻路的实现

    这篇文章主要为大家介绍了C++ 基于BFS算法实现走迷宫自动寻路,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • C++ opencv利用grabCut算法实现抠图示例

    C++ opencv利用grabCut算法实现抠图示例

    这篇文章主要为大家介绍了C++ opencv利用grabCut算法实现抠图的代码示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • c++ 头文件<cwchar>中常见函数的实现代码

    c++ 头文件<cwchar>中常见函数的实现代码

    本文记录了c++ 头文件<cwchar>中常见函数的实现,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-12-12
  • C++超细致讲解队列queue的使用

    C++超细致讲解队列queue的使用

    队列先进先出,即只能在容器的末尾添加新元素,只能从头部移除元素,下面这篇文章主要给大家介绍了关于C++中队列queue用法的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • C++ 多继承详情介绍

    C++ 多继承详情介绍

    这篇文章主要介绍了C++ 多继承详情,C++支持多继承,即允许一个类同时继承多个类。只有C++等少数语言支持多继承,下面我们就来看看具体的多继承介绍吧,需要的朋友可以参考一下
    2022-03-03
  • C语言分装实现三子棋游戏详解

    C语言分装实现三子棋游戏详解

    这篇文章主要为大家详细介绍了C语言分装实现三子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • 数组和指针的区别深入剖析

    数组和指针的区别深入剖析

    在C/C++中,指针和数组在很多地方可以互换使用,这使得我们产生一种错觉,感觉数组和指针两者是完全等价的,事实上数组和指针是有很大的区别的
    2012-11-11
  • C语言中volatile关键字的作用与使用案例教程

    C语言中volatile关键字的作用与使用案例教程

    这篇文章主要介绍了C语言中volatile关键字的作用与使用案例教程,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是本文的详细内容,需要的朋友可以参考下
    2021-07-07
  • 判断本机office安装版本的方法分享

    判断本机office安装版本的方法分享

    这篇文章主要介绍了判断本机office安装版本的方法分享,需要的朋友可以参考下
    2014-01-01

最新评论