C语言程序设计学习

1.定义和声明最重要的区别:定义创建了对象并为这个对象分配了内存,声明没有分配内存

2.static
变量
静态局部变量:作用域在函数内,保存在内存的静态存储区,只被初始化一次,在下一次调用前还可以保持原来的赋值
静态全局变量:作用域在定义的文件内

函数
对于函数而言,任何用static修饰的函数,其作用域仅为当前源文件,而对外部来说这个函数是不可见的,即只有和其在同一源文件中的函数才能调用这个静态函数;
反过来说,如果一个函数仅仅被同一源文件中的其他函数调用,那么这个函数应该声明为静态的,这样做的好处在于:可以一定程度上的解决不同源文件之间函数的命名冲突问题;

3.sizeof是披着函数皮的关键字
sizeof()包含最后的结束符’\0′
strlen()只计算字符串中元素个数,不包含’\0′
sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以’\0’结尾的

4.原码补码反码
对于有符号数据来说
[X1]原=[+1010110]原=01010110
[X2]原=[-1001010]原=11001010
原码:其符号位用0表示正号,用1表示负号,数值一般用二进制形式表示。
反码:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
补码:正数的补码与其原码相同;负数的补码是在其反码的末位加1。

5.switch…case…
case后面只能是整型或字符型的常量或常量表达式

if语句 switch语句 要把正常的情况放前面,把异常的情况放后面

6.break和continue
break表示终止本层循环。
continue表示终止本次(本轮)循环。

7.合理慎用goto
goto语句可以灵活跳转

8.void
void类型的指针,可以无需强制类型转换赋值给其它类型的指针
void用来修饰函数没有返回值,没有参数

void *指向任意类型的指针,如果函数的参数可以是任意类型指针,应声明其参数为void *
memset 原型:extern void *memset(void *buffer, int c, int count);
memcpy 原型:extern void *memcpy(void *dest, void *src, unsigned int count);
比如memcpy可以,结构体对拷,数组对拷,变量对拷,任何类型对拷。

memcpy和strcpy区别,参数一个是void *,一个是char *,一个是任何类型一个是字符型
memcpy返回值也是void *任何类型,strcpy返回值是char *字符型

9.return
return不能返回指向“栈内存”的指针,因为该内存在函数体结束时被自动销毁。

10.const常量
const表示该变量是只读变量readonly

11.extern
extern可置于变量或函数前,以标识变量或函数的定义在别的文件中

12.struct union enum
union只配置一个足够大的空间来容纳最大长度的数据成员,所有数据成员具有相同的起始地址

enum Color
{
GREEN=1,
RED,
BLUE,
GREEN_RED=10,
GREEN_BLUE
}ColorVal;

13.typedef
typedef是给一个已经存在的数据类型取一个别名,尤其是给结构体之类的自定义数据类型

14.注释
注释位置在语句同一行,也可在上行,但不可放在下行

15.\ 接续符
\表示断行,编译器会将反斜杠剔除掉,跟在反斜杠后面的字符自动接续到前一行

16.条件编译
第一种形式:
#ifdef 标识符
程序段 1
#else
程序段 2
#endif

第二种形式:
#ifndef 标识符
程序段 1
#else
程序段 2
#endif

第三种形式:
#if 常量表达式
程序段 1
#else
程序段 2
#endif

每个.h文件开始都有#ifnedf XXXX 下一行#define XXXX,文件最后#endif,是为了防止头文件重复包含

17.指针
一个基本的数据类型(包括结构体等自定义类型)加上*号就构成了一个指针类型的模子
在32位系统下,不管什么样的指针类型,大小都为4字节

18.思考问题解决问题
把没见过的、不会的问题想方设法转换成你见过的、你会的问题

19.&a[0]和&a
&a[0]是数组首元素的首地址
&a是数组的首地址,数组名a代表数组首元素的首地址,和&a[0]一样
虽然它们的值一样

20.
int a[5]={1,2,3,4,5);
int *p = a+1; //2
int *p2 = &a+1; //越界,这里把a当成一个整体来看

21.指针和数组
数组就是数组,指针就是指针,它们是完全不同的两码事!它们之间没有任何关系。

22.数组指针和指针数组
指针数组:int* p1[10],首先它是一个数组,数组的每个元素是指针
数组指针:int (*p2)[10],首先它是一个指针,它指向一个包含10个int类型的数组

23.
C语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针

24.
函数本身是没有类型的,只有函数的返回值才有类型

25.
函数名就是函数的入口地址
函数名就是函数的地址,函数名的值保存为这个函数的地址
int add(int a,int b)
{

}是一个函数
int (*fp) (int a, int b);是函数型指针
fp = add;
使用时fp(3, 4)和(*fp)(3, 4)效果是一样的

26.
[]的优先级比*要高
char*(*pf[3])(char*)
pf是一个有3个元素的数组,数组内存储了3个指向函数的指针,这个函数的参数是char *,返回值是char *

char*(*(*pf)[3])(char *p)
pf是一个指针,指向一个包含3个元素的数组,数组的每一个元素是指向函数的指针,被指向的函数参数是char*,返回值是char *

27.
char (*pf)[5],指向数组的指针
char a[5] = {1,2,3,4,5};
pf = &a;
指针和数组都能以指针的形式访问和以下标的形式访问
以下标的形式访问指针:pf[0][3],编译器会把以下标形式的操作解析为以指针形式的操作
取第2个元素:p[0][3]、 (*p)[3]、*(*(p+0)+3)效果一样

28.
不管什么时候,我们使用指针之前一定要确保指针是有效的

29.
for循环的循环变量一定要使用半开半闭的区间,循环变量尽量从0开始

30.
会产生泄漏的内存就是堆上的内存,是程序员手工分配、释放的内存

31.
习惯将函数参数顺序,目的参数放在前面,源参数放在后面
str_copy(str,”Hello World!”);

32.
return语句不能返回指向“栈内存”的“指针”(指向局部变量),因为它的生命周期在函数体结束时被自动销毁

33.
需要对外公开的常量放在头文件中(.h中),不需要对外公开的常量放在定义文件的头部(.c中)

34.大小端模式
字数据从小到大是从右往左的,地址从小到大是从左往右的
100000 (从低到高)大端模式为 10 00 00(大端模式按照自数据的本来顺序存)
100000 小端模式为 00 00 10(小端模式按照地址从小到大存)
大端模式:字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中
小端模式:字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中
APM架构下保存数据是用小端模式
intel架构下是用大端模式

35.内存的三个部分
静态区:保存自动全局变量和static变量(包括static全局和局部变量)。静态区的内容在整个程序的声明周期内都存在,由编译器在编译的时候分配。
栈:保存局部变量。栈上的内容只在函数的范围内存在,当函数运行结束,这些内容也会自动被销毁。
堆:由程序员手工分配,释放的内存。在没释放之前一直存在,直到程序结束。

36.全局变量有哪些?
在函数外部定义的变量(用extern声明,extern语句不分配内存)。
static变量(包括static全局和局部变量)。
const定义的只读变量是全局的只读变量,存放在静态区。

37.return
return语句直接跳出函数。

38.main函数参数
main函数参数是操作系统给它的。我们终端机上是control层给main函数这两个参数。
main(BYTE cmd, BYTE *cmd_buf)
cmd是命令类型,cmd buffer是功能的数字

39.goto语句
goto语句的标号,即使没有goto到那里,在顺序执行中遇到,也会执行下去。

40.if和else if
if(表达式1)
语句1
else if(表达式2)
语句2

如果if后面的表达式1为真,则执行语句1,后面的else if语句不再执行。

41.&与运算
与运算用来判断一个字节的哪一个为1,1个BYTE值&0x40,就可以看它第7位是不是为1。
规则:如果两个相应的二进位都为1,则该位的结果值为1,否则为0。
注意:整个与运算的结果不是1和0,此处应是0x40和0。

42.^异或运算
0和0x01异或就变为1,再和0x01异或又变为0。
规则:若参加运算的两个二进位同号,则结果为0(假),异号则为1(真)。
异或没有先后顺序。

43.|或运算
有一个BYTE要把第6位设为1,1个BYTE值|0x20,相同位与1做或运算,就可以把它某一位设为1了。
规则:两个相应的二进位中只要有一个位1,该位的结果值为1。

44.<<左移运算
右边补0

45.高底位
Bit4-7 Bit0-3 高位在前
XXXXXXXX
76543210

46.return 0和1
被调函数 return 1;只是给主调函数一个标志,说明他的执行过程中遇到异常情况。
然后就返回主调函数来处理,继续执行。
return 跳到函数外
return 0代表函数正常终止
return 1代表函数非正常终止

47.
确保函数参数类型的正确性是程序员的责任。
单个字符是数值型的另一种表现形式。

48.C语言内存观
在内存中存储的数据都是以二进制形式,比如有一个字节11110001。
把它看成十六进制就是0xF1,看成十进制就是数值241,看成有符号的数值就是-113,
看成ASCII码是一个不可显示的字符(ASCII码范围是数值0-255),看成BCD码就是由0x0F和0x01组成的。

49.
BOOLEAN xxxxxx (void)
函数执行成功就return TRUE,失败就return FALSE

50.
extern和static
(1) extern 表明该变量在别的地方已经定义过了,在这里要使用那个变量。
(2) static 表示静态的变量,分配内存的时候,存储在静态区,不存储在栈上面。

51.
数组作为函数参数的时候传的都是地址,不论是用哪种形式
int a[SIZE]
int a[1000]
int a[]

52.如何获得指针指向字符串的长度
BYTE * ptr = “abcde”;
用strlen((char *)ptr)

53.#define __T(x) L##x
“##”是ANSI C标准的预处理语法,它叫做“粘贴符号”,表示将前面的L添加到宏参数上。
也就是说,如果我们写__T(“Hello”),展开后即为L”Hello”

54.函数指针和指针函数
指针函数定义的是一个函数,它的返回值是一个指针。
int * func (int)

函数指针定义的是一个指针,指向了一个特定类型的函数。
int func(int x); //声明一个函数
int (*f) (int x); //声明一个函数指针f是指向返回值为int型,带一个int型参数的函数
f=func; //将func函数的首地址赋给指针f

signal函数
void ( *signal(int sig, void (*func)(int)) ) (int);
signal函数有两个参数,一个是int型的sig,一个是指向返回值为void,带一个int型参数的函数指针。
它的返回值是一个函数指针,所指向的函数接受一个int参数并返回void。

55、比较两个浮点型变量大小
由于浮点型变量有精度问题,不能直接用>、<比较大小,所以要用两个数相减是否大于或小于一个极小的数。
例如:(float)a – (float)b > 0.0005