【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