【C语言学习笔记】
C语言发展史:
-  
1960 原型A语言->ALGOL语言
 - 1963 CPL语言
 - 1967 BCPL
 - 1970 B语言
 - 1973 C语言
 
C语言特点:
- 基础性语言
 - 语法简洁 紧凑 方便 灵活(得益于指针)
 - 运算符 数据结构丰富
 - 结构化 模块化编程
 - 移植性好 执行效率高
 - 允许直接对硬件操作
 
C语言学习建议:
- 概念的正确性
 - 动手能力
 - 主动阅读优秀的程序段
 - 大量练习,面试题,编程是技术不是理论
 
C课程讲解思路:
- 基本概念
 - 数据类型 运算符 表达式
 - 输入输出
 - 流程控制
 - 数组
 - 指针
 - 函数
 - 构造类型
 - 动态内存管理
 - 调试工具(gdb、make)和调试技巧
 - 常用库函数
 
平台介绍:
64位的redhat6,vim(编辑器),gcc(make)
hello.c:"Hello world"
#inlcude <stdio.h>
#include <stdlib.h>int main(void){printf("hello world!\n");exit(0);
} 
编译器gcc:
C源文件->预处理->编译->汇编->链接->可执行文件
完整过程
- 预处理
 
gcc -E hello.c > hello.i 
- 编译
 
gcc -S hello.i  
- 汇编
 
gcc -c hello.s  
- 链接->可执行文件
 
gcc hello.o -o hello 
或者
gcc hello.c -o hello 
又或者
make hello 
执行
./hello 
编辑器vim:
vim配置脚本以及常用快捷方式
一、基本概念
1、以helloworld为例对写程序的思路提出如下要求:
1)头文件正确包含的重要性
在c中,如果没有出现函数原型,就默认函数的返回值是int
#include <stdio.h>
#include <stdlib.h>//malloc存在的头文件
int main()
{int *num = (int *)malloc(sizeof(int));//包含头文件后就不需要强制类型装换了return 0;
} 
2)以函数为单位来进程程序编写
3)声明部分+实现部分
4)return 0;
5)多用空格空行
6)添加注释
1、
//2、
/*    */3、
/******/4、在预处理的时候不参与编译
#if 0#endif 
2、算法:解决问题的方法(流程图、NS图、有限状态机FSM)
3、程序:用某种语言实现算法
4、进程:
5、防止写越界、防止内存泄漏、谁打开谁关闭、谁申请谁释放
二、数据类型、运算符和表达式
1、数据类型(基本数据类型)
- 基本类型 
- 数值类型 
- 整型 
- 短整型 short
 - 整型 int
 - 长整型 long
 
 - 浮点型 
- 单精度型 float
 - 双精度型 double
 
 
 - 整型 
 - 字符类型 char
 
 - 数值类型 
 - 构造类型 
- 数组
 - 结构体 struct
 - 共用体 union
 - 枚举类型 enum
 
 - 指针类型
 - 空类型 void
 
1)所占节数

2)存储区别
整型数的存储都是以补码形式来进行存储的
254 -> unsigned int -> 32bit
-254 -> 取绝对值 254  -> 1111 1110 取反 + 1(254)10 = (1111 1110)2 = (376)8 = (FE)16254
B11111110(c不认识这个表示)
0376
0xFE浮点类型存储方式
0.314*10^1
0~32:0~22(23位):记录精度部分23~30(8位):存储指数部分31(1位):符号位字符类型
存储的是二进制形式(ASCII码表)0~127 前128个都是标准C规定的ASCII码值情况 128~255 是补充进来的
字符   十进制 十六进制
0      048     30
A      065     41
a      097     61 
3)不同类型的数据间进行转换(隐式、显式->强制类型转换)
隐式
int i;
float f;
doubel d;
char ch;ch + i -> i
f -d -> d(ch + i) - (dloat -double) -> double
 
4)特殊性:
(1)布尔型bool
逻辑真、逻辑假
#incldue <stdio.h>
#include <stdlib.h>
#include <stdbool.h>int main() {bool a = false;printf("a = %d\n", a);exit(0);
} 
(2)float类型
浮点型的失真问题
int func(float f) {if (f < 0) {return -1;} else if (fabs(f-0) <= 1e-6) {return 0;} else {return 1;}
} 
(3)char型是否有符号
                        c中 char有无符号是未定义行为
(4)不同形式的0值:0、‘0’、“0”、‘\0’
0(整形) '0'(字符常量) "0"(字符串常量) '\0'(字符常量) 
(5)数据类型与后续代码中所使用的输入输出要相匹配(防止自相矛盾)
#include <stdlib.h>
#include <stdio.h>int main() {unsigned int a;//无符号a = 1 << 31;printf("%ud", a);//无符号
}
 
2、常量与变量
1)常量:在程序执行过程中值不会发生变化的量
分类:整型常量、实型常量、字符常量、字符串常量、标识常量
- 整形常量: 1 、52、752
 - 实型常量: 2.2 、3.14、1.9999
 - 字符常量(由单引号引起来的单个的字符或转义字符): 'a'、'X'、'\t' 、'\n'、 '\0' 、'\015'(8进制)、 '\x7f' (16进制)、'\018'(错误的表示,八进制不会出现8!!)

 - 字符串常量(由双引号引起来的一个或多个字符组成的序列): ""(空串:尾0)、 "a" 、"abXYZ"、 "abc\n\021\018"(a b c \n \021 \0 1 8)
 - 标识常量:#define 宏名 宏体,处理在程序的预处理阶段,占编译时间,优点:一改全改,缺点:不检查语法,只是单纯的宏体与宏名之间的替换
 
#include <stdlib.h>
#include <stdio.h>#define PI 3.1415926
#define ADD 2+3
// 正确写法
//#define ADD (2+3)
int main() {printf("%f\n", PI);printf("%d\n", ADD * ADD);
}
 
#include <stdlib.h>
#include <stdio.h>#define MAX(a,b) ({typeof(a) A=a,B=b; ((A) > (B) ? (A) : (B));})int main() {int a = 3, b = 5;printf("%d\n",MAX(a++, b++));printf("%d\n",MAX(a++, b++));
}
 
在程序的预处理阶段,占编译时间,不占运行时间(没有函数调用的消耗),但不检查语法(比较危险)
2)变量:用来保存一些特定内容,并且在程序执行过程中值随时会发生变化的量
定义:[存储类型] 数据类型 标识符 = 值
TYPE NAME = VALUE;
标识符:由字母,数字,下划线组成且不能以数字开头的一个标识序列。写标识符尽量做到 见名生义。
数据类型:基本的数据类型+构造类型
值:注意匹配
存储类型:auto、 static、 register、 extern(说明型)
auto: 默认,自动分配空间,自动回收空间
register :(建议型)寄存器类型,只能定义局部变量,不能定义全局变量,大小 有限制,只能定义32位大小的数据类型,比如double就不可以。因为寄 存器没有地址,所以一个register类型的变量无法打印出地址查看或使用
static:静态型,自动初始化为0值或空值,并且static变量的值有继承性。另外常 用来修饰一个变量或者函数(防止当前函数对外扩展)
#include <stdlib.h>
#include <stdio.h>void func() {static int x = 1;x++;printf("%d\n", x);
}int main() {func();func();func();
}2
3
4 
extern: 说明型,意味着不能改变被说明的量的值或类型 可以用来扩展外部变量 的作用域
main.c
#include <stdio.h>
#include <stdlib.h>#include "proj.h"int i = 10;int main()
{printf("[%s]:i = %d\n",__FUNCTION__,i);func();exit(0);
}
 
proj.c
#include <stdio.h>
#include <stdlib.h>#include "proj.h"void func(void)
{printf("[%s]:i = %d\n",__FUNCTION__,i);exit(0);}
 
proj.h
#ifndef PROJ_H__
#define PROJ_H__extern int i;
void func(void);#endif
 
变量的生命周期和作用范围
(1)全局变量和局部变量
(2)局部变量和局部变量
(3)参考图片

3、运算符和表达式
表达式与语句的区别
表达式 i = 1   i= j*2
语句   i = 1; i= j*2; 
运算符部分:
1)每个运算符所需要的参与运算的操作数个数
2)结合性
3)优先级

4)运算符的特殊用法
如:%:必须是整数
=(赋值)与==(比较)
逻辑运算符的短路特性(&& :前面为假,||:前面为真,后面都不需要计算了)
#include <stdio.h>
#include <stdlib.h>int main() {int a = 1, b = 2, c = 3, d = 4;int m = 1, n = 1;(m = a > b) && (n = c > d);printf("m = %d\n n = %d\n", m, n); // m : 0 n : 1
} 
5)位运算的重要意义
- | 按位或
 - & 按位与
 - ^ 按位异或:相同为0,不同为1
 - ~ 按位取反
 
应用
将操作数中的第n位置1 其他位不变 num = num | 1 << n;
将操作数中的第n位置0 其他位不变 num = num & ~(1<<n);
测试第n位: if(num & (1<<n))

求字节数:sizeof
#include <stdio.h>
#include <stdlib.h>int main() {printf("%lu, %lu, %lu, %lu, %lu, %lu, %lu\n",sizeof(int),sizeof(short), sizeof(long),sizeof(double), sizeof(float), sizeof(char), sizeof(void*));
}4, 2, 8, 8, 4, 1, 8
 
 
自增、自减
运算符在前,先进行计算,再取变量值使用
变量在前,先取变量值使用,再进行计算
int i = 1, j = 2, value;
value = i++ + ++j 
