《C语言深度解培》读书笔记之一

    前言:

    听明白,看明白并不代表你懂了,你懂了不代表你会用了,你会用了不代表你会用明白,你能用明白并不代表你真正懂了!什么时候表明你真正懂了呢?你站到我这来,把问题给同学讲明白,学生们听明白了,说明你真正懂了。否则你就没有真正懂,这是检验懂没懂的唯一标准。
    从现在开始,除非在特殊的情况下,不允许使用printf函数。
    永远记住一点:结果对,并不代表程序真正没有问题。
    参考书:《The C Programming Language》 
            《Expert C Programming》
            《C Traps and Pitfalls》
            《Write Clean C Code》
            《Code Complete,Second Edition》
            《高质量C++/C编程》
------------------------------------------------------------------------------------------
1.C语言的关键字有多少个?并在下面写出来。
C语言的关键字有32个
auto register static extern  volatile const  存储级别6个
void int char float double                  基本类型5个
short long signed unsigned                  类型修饰4个
enum  union struct  typedef sizeof         复杂类型5个
if else switch case default for do whilebreak continue return goto  流控制 12个

注意:define不是关键字。
2.什么是定义?什么是声明?它们有何区别?
所谓定义就是(编译器)创建一个对象,为这个对象分配一块内存并给它取上一个名字,这个名字就是我们经常所说的变量名或对象名。但注意,这个名字一旦和这块内存匹配起来,它们就同生共死,不离不弃。并且这块内存的位置也不能被改变。一个变量或对象在一定的区域内,只能被定义一次,如果定义多次,编译器会提示你重复定义同一个变量或对象。
什么是声明,有两重定义,如下
第一:告诉编译器,这个名字已经匹配到一块内存上了,下面的代码用到变量或对象是在别的地方定义的,声明可以出现多次。
第二:告诉编译器,我这个名字我先预定了,别的地方再也不能用它来作为变量名或对象名。这种声明最典型的例子就是函数参数的声明。
定义声明最重要的区别:定义创建了对象并为这个对象分配了内存,声明没有分配内存。

register:这个关键字请求编译器尽可能的将变量存在cpu内部寄存器中而不是通过内存寻址访问以提高效率。

虽然寄存器的速度非常快,但是使用register修饰符也有些限制的;register变量必须是被cpu寄存器所接受的类型。意味着register变量必须是一个单一的值。并且其长度应小于或等于整型的长度。而且register变量可能不存放在内存中,所以不能用"&"来获取register变量的地址。

static:
第一个作用:修饰变量。变量又分为局部和全局变量。
静态全局变量:作用域仅限于变量被定义的文件中,其他文件既使用extern声明也没法使用它,准确地说其作用域是从定义之处开始,到文件结尾处结束。在定义之处前面的那些代码也不能使用它。想要使用就得在前面加上extern.
静态局部变量:在函数体内定义的,就只有在这个函数里用了,同一个文件中的其他函数也用不了,由于被static修饰的变量总是内存的静态区,所以即使这个函数运行结束,这个静态变量的值还是不会被销毁,函数下次使用时,仍然能用这个值。

第二个作用:修饰函数。
函数前面加上static使得函数成为静态函数,但此处的"static"的含义不是指存储方式,而是指对函数的作用域仅限于本文件(又称内部函数)。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数是否与其它文件中的函数同名。

一个函数名禁止被用于其他用处。
定义变量的同时千万别忘记了初始化。定义变量时编译器并不一定清空了这块内存,它的值可能是无效的数据。

不同类型数据之间的运算要注意精度扩展问题,一般低精度的数据向高精度的数据扩展。

sizeof

sizeof在计算变量所占空间大小时,括号可以省略,而计算类型(模子)大小时不能省略。一般情况下都加上括号。

sizeof的用途必须得掌握。程序员笔试题目中也会经常考察其有关的用法。

#与存储分配和I/O系统的例程进行通信。

#查看某个类型对象在内存中所占的单元字节。

#便于一些类型的扩充,在windows中,很多结构类型有一个专用的字段是用来存放该类型字节的大小。

#在涉及琶操作数字节大小时,用sizeof来代替常量计算。


signed和unsigned关键字

约定:如果最高位是1,表明这是个否数,如果最高位是0,表明这个数是正数。

参阅《计算机组成原理》中所讲的关于数据在内存中是如何存放的。

#include <stdio.h>
#include <string.h>
#include <conio.h>
int main(void)
{
	char a[1000];
	int i;
	for (i=0;i<1000;i++)
	{
		a[i]=-1-i;
	}
	printf("%d\n",strlen(a));
	getch();
	return 0;
}

答案是255

留的问题:
1.+0和-0在内存里分别怎么存储
2.int i=-20;
  unsigned j=10;    //计算i+j的值是多少?为什么?
3.下面的代码有什么问题?   //死循环
unsigned i;
for(i=9;i>=0;i--)
{
    printf("%u\n",i);
}

if语句后面的分号

case后面只能是整型或字符型的常量或常量表达式,(想想字符型数据在内存中是怎么存的)
在switch-case语句中能否使用continue关键字?为什么
答:不能。除非switch-case语句中有循环。continue是加速循环使用的语句。

任何类型的指针都可以直接赋值给void *的指针,无需进行强制类型转换。
但是并不意味着,void *也可以无需强制类型转换赋给其它类型的指针。

void指针
如果函数的参数可以是任意类型指针,则应声明其函数为void *.

被const修饰的是变量是只读变量,注意不是常量。

const修饰的只读变量为什么必须在定义的同时初始化?
定义的时候就把它的内存空间给限制死了,要是不初始化,那块区域永远就是那个样子了。
编译器通常不为普通const只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。
const定义的只读变量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define给了了立即数,所以,const定义的只读变量在程序运行过程中只有一份拷贝,(因为它是全局的只读变量,存放在静态区),而#define定义在宏常量 在内存中有若干个拷贝。
volatile
volatile可以保证对特殊地址的稳定访问。
volatile是与编译器优化相关的关键字。
struct(结构体
struct它将一些相关联的数据打包成一个整体,方便使用。
一个空的结构体所占的空间是多大呢?
柔性数组
struct与class的区别
struct:数据成员默认为public属性,只含数据,不含操作。
class:数据成员默认为private属性。可以包含操作,class还可以表模板类型而struct则不能。
struct与union的区别
(a)struct变量所占内存长度是名成员所占内存长度之和,另需考虑内存对齐,每个成员都有自己的内存单元。
   union变量所占内存长度等于最长的数据成员长度。
(b)对于struct的不同成员赋值是互不影响的,
   而对于union的不同成员赋值,将会对其他成员重写,原来的值就不存在了。
union(共用体)
union主要用来压缩空间。如果一些数据不可能在同一时间被用到,则可以使用union.
一个union只配置一个足够大的空间以来容纳最大长度的数据成员。
大小端模式对union类型数据的影响
大端模式(Big_endian):字数据的高字节存储在低地址上,而字数据的低字节则存放在高地址中。
小端模式(Little_endian):字数据的高字节存储在高地址上,而字数据的低字节则存放在低地址中。
union型数据所占的空间等于其最大数据成员的占的空间。
对union型的成员的存取都是相对于该联合体基地址偏移量为0处开始,也就是联合体访问不论对哪个变量的存取都是从union的首地址位置开始的。
编写一个函数,如果处理器是big_endian的,则返回0,若是littel_endian的,则返回1.
#include <stdio.h>
#include <conio.h>
int checksystem(void);
int main(void)
{
	int n;
	n=checksystem();
	if (n==1)
	{
		printf("BIG\n");
	}
	else
	{
		printf("LITTEL\n");
	}
	getch();
	return 0;
}
int checksystem(void)
{
	union check
	{
		int i;
		char ch;
	}c;
	c.i=1;
	return (c.ch == 1);
}

有的系统同时支持两种存储模式,你可以用硬件跳线或在编译器的选项中设置存储模式。
enum(枚举)
所谓enum就是将变量的值一一列举出来,变量的值仅限于在列举出来的值的范围内。
可以把一个枚举变量的值直接赋值一个整型变量。
枚举类型会转换为相应的类型,但数据类型不能自动转换为枚举类型。
enum与#define的区别
#define是在预编译阶段进行简单的文本替换,而enum是在编译的时候确定其值。
一般在编译器里,可以调试枚举变量,但是不通调试宏常量。
枚举可以一次定义大量相关的常量,而#define宏一次只能定义一个。

typedef
博大精深
typedef是为已有的类型建立一个或多个别名,而不是新建一个类型,不要被字面意思误导。
使用typedef可以增加程序的可移植性。
用typedef定义的数据类型变量不能用signed,unsigned,short,long等关键字来修饰,typedef没有宏的自扩展性。
<事后专门补习typedef的用法>
第一章中主要介绍了C中32个关键字的一些特性及用法,对于这些最基本的东西,在概念上一定要彻底弄清楚是怎么回事,多问几个为什么,多思考一下不同之处。


  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值