C语言程序设计1
计算机语言分类:
-
机器语言:(machine language)计算机直接使用的二进制形式的程序语言或机器代码。
-
汇编语言:借助助记符进行描述的计算机语言。
-
高级语言:(high-level language)是易于人们所理解的完全符号化的程序设计语言。 例如:C、C++、Java语言
写代码的过程:
-
编辑器: 程序员写代码的过程(记事本、vc6.0、vim)
-
编译器:查看代码的语法错误,生成汇编语言。
-
汇编器:将生成好的汇编语言生成二进制语言(目标文件)
-
连接器:将生成好的 二进制语言+用到的库+启动代码 ==>可执行文件
案例1:C语言的结构
-
函数是C程序的基本单位。函数由 函数头 和 函数体 组成,函数头包括***返回值类型***、函数名、参数,注意:不管是否存在参数,函数名后的圆括号必须存在。函数体由***花括号*** 括起来,函数体由多条语句构成。
-
main函数:一个C程序从main函数开始执行,到main函数体执行完结束,而不论main函数在整个程序中的位置如何。每一个程序有且仅有一个main函数,其他函数都是为main函数服务的。
-
\n:表示换行,即本行结束时,后面的语句从下一行开始。
-
函数体中以分号结尾的为语句。
-
注释:是对程序的说明,可出现在程序中任意合适的地方,注释从“/”开始到最近一个“/” 结束,其间任何内容都不会被计算机执行,注释不可以嵌套。其中 单行注释 为//,***多行注释*为//。
-
书写格式,每条语句的后面必须有一个分号,分号是语句的一部分。一行内可写多条语句,一个语句可写在多行上。
#include<stdio.h> //std标准 i输入 o输出(标准输入输出头文件) /* 以.h为后缀的文件被称为头文件,可以是 C 程序中现成的标准库文件,也可以是自定义的库文件。 #include:表示预处理命令,可有可无,如果存在,放在程序的开头,处理对象为文件。 mian函数 称为主函数 是程序的入口,有且仅有一个 mian 左边的int代表的是函数的返回值类型 ()里面函数的形参(函数外部将数据传递到函数内部的桥梁) */ int main(int magc, char *argv[]) { //函数的功能都是在{}里面实现 //使用任何东西 必先存在 //printf:将""中的字符串 输出到 终端上 //printf()为输出函数,将内存中数据显示到屏幕上,显示的内容用英文双引号括起来。 printf("hello ito\n"); return 0; //如果代码一闪而过 可以用阻塞的代码(while(1);)/(getchar();) }
案例2:求圆的面积
-
知道圆的半径r
#include<stdio.h> #define PI 3.14//宏定义 int main() { float r = 0.0f;//定义一个变量 系统给r开辟4字节空间。 float area = 0.0f; printf("请输入半径r的值:"); scanf("%f", &r);//带阻塞 area = PI*r*r; printf("area=%.2f\n", area);//输出数据两位小数。 return 0; }
案例3:用分函数的方式求两个数的和
-
定义一个函数 去 计算上面两个变量data1和data2的和 在 函数内部计算(怎么将数据 传递 到函数内部呢?)
需要用形参 将data1和data2传递到 函数内部
-
得到函数内部的计算结果(怎么得到呢?)
通过函数的返回值 得到函数的计算结果
#include<stdio.h> int add_fun(int a,int b) { return a+b; } int main(int argc,char *argv[]) { int data1 = 0, data2 = 0; int ret = 0;//存放函数的结果 printf("请输入两个整数:"); scanf("%d %d",&data1,&data2); //函数的调用 ret = add_fun(data1,data2); //a = data1,b = data2 //输出ret的结果 printf("ret = %d\n", ret); return 0; }
练习1
练习1:通过C语言的基本结构,输出学生的姓名、性别和年龄
练习2:计算长方形的面积
(思路)1.接收用户输入的长方形长度和宽度两个值;
2.判断长度和宽度的值是否大于零;
3.如果大于零,将长度和宽度两个值相乘得到面积,否则显示输入错误;
4.显示面积。
算法和流程图
-
算法:解决问题的具体方法和步骤
-
算法的五个特性:
-
有穷性:对于任意一组合法输入值,在执行有穷步骤之后一定能结束,而且每一步都能在有限时间内完成。
-
确定性:算法中每一条指令必须有确切的含义,不应该具有二义性。并且在任何条件下,对于相同的输入只能得到相同的输出。
-
可行性:算法中描述的操作都可以通过已经实现的基本操作执行有限次来实现
-
输入:一个算法有0个或多个输入,这些输入都是来自某个特定的对象的集合。
-
输出:一个算法有1个或多个输出,这些输出都是与输入有着某些特定关系的值。
-
-
流程图
- 流程图是算法的一种图形化表示方式,它使用一组预定义的符号来说明如何执行特定任务
C语言程序执行过程
-
程序:为解决某一问题而设计的一系列指令,能被识别并执行。
-
用C语言编写的程序称为C语言源程序,源程序文件的后缀名为“.c”或“.cpp”。
-
源程序经编译后生成后缀名为“.obj”的目标文件,再把目标文件与各种库函数连接起来,生成“.exe”可执行程序。
-
C语言有三种基本结构:顺序结构、选择结构、循环结构
-
#include“stdio.h”
与#include<stdio.h>
的区别?当要调用某个函数时:
#include"stdio.h"
先在用户自已编写的文件中查找,如果找不到再到库文件里去找.#include<stdio.h>
是直接到库文件里去找- 所以如果是调用自己写的函数的话就用
#include"stdio.h"
,这种形式。 - 而调用标准库函数的话就用
#include<stdio.h>
这种形式,可以提高速度。
-
编译预处理:
-
在C语言的源程序中,除说明语句和可执行语句以外,还有一种特殊语句—预编译语句
作用:告诉编译系统,在正式编译源程序之前,需做什么预处理工作。其在词法扫描和语法扫描之前所做的工作。
-
-
预处理命令包括:文件包含、宏定义 和 条件编译
-
特征:行首以#号开头
-
文件包含命令的一般形式:#include “文件名”
-
文件包含命令的功能是将指定文件插入该命令位置取代该命令行,从而将指定的文件和当前的源程序文件连接成一个源文件。
-
文件包含命令用法需注意:
1、包含文件的文件名可以用双引号或尖括号括起来。
2、一个include命令只能指定一个包含命令,若有多个文件包含,则需多个include命令。
3、文件包含允许嵌套,即在一个包含的文件中可以包含一个文件
-
-
宏定义:
- 在C语言源程序中可用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“宏名”。
- 在编译预处理时,对程序中所有出现的“宏名”,都用宏定义的字符串去代换,此称为“宏代换”或“宏展开”。
- 宏定义是源程序中的宏定义命令完成,宏代换由预处理程序自动完成.
-
“宏”分为有参和无参数
-
不带参数的宏定义
形式: #define 标识符 字符串
“#”表示是一条预处理命令 define宏定义命令
标识符:为所定的宏名 字符串:可以是常量、表达式等
例如:
# define M (y*y+3*y)
# define M y*y+3*y
# define PI 3.14159
-
不带参数宏定义需说明以下几点:
- 宏定义用宏名表示字符串,宏展开以字符串取代宏名。预处理程序不对宏定义作任何检查。若要错误,只在编译以展开的源程序时发现。
- 宏定义不是说明或语句,行末不接分号。
- 宏定义必须写在函数之外,作用从宏定义命令到源程序结束 为止,若提前终止,使用
#undef
命令。 - 宏名在源程序中用引号括起,则预处理程序不对其作宏代换。
- 宏定义允许嵌套,在宏定义的字符串可以使用已定义的宏名。
- 习惯上宏名用大写字母表示,但也允许用小写字母表示。
- 宏替换不占用运行时间。
-
带参数的宏定义
-
C语言允许带有参数。宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。
-
带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。
-
形式:
#define 宏名(形参表) 字符串
-
在字符串中含有各个形参; 例如:
#define M(y) y*y+3*y
-
带参宏调用的一般形式: 宏名(实参表);例:k=M(5);
-
-
对带参数的宏定义有以下说明:
- 带参宏定义中,宏名和形参之间不能有空格。
- 在带参宏定义中,形参不分配内存空间,不必作类型定义。而宏调用中的实参有具体的值。用它们去替换形参,必作类型说明。
- 宏定义的形参是标识符,而宏调用的实参是表达式。
- 宏定义中,字符串内的形参用括号括起来。
-
数据类型
关键字(32个)
-
数据类型关键字(12个)
char, short, int, long, float, double, unsigned, signed, struct, union, enum, void
-
控制语句关键字(12个)
if, else, switch, case, default, for, do, whlie, break, continue, goto, return
-
储存类关键字(5个)
auto, extern, register, static, const
-
其他关键字(3个)
sizeof, typedef, volatile
知识点1【数据类型】
-
数据的不同类型 目的 合理的利用空间
-
计算机储存的是***二进制***,一位二进制 只能存放0或1
-
1字节 == 8bit(八位二进制)0000 0000~1111 1111
1B == 8b 1TB == 1024GB
1KB ==1024B 1PB ==1024TB
1MB ==1024KB 1EB ==1024PB
1GB ==1024MB
---------------------在32位平台--------------------------
char 字符类型 占1字节的空间 (8位二进制位)
short 短整型 占2字节的空间 (16位二进制位)
int 整型 占4字节的空间 (32位二进制位)
long 长整型 占4字节空间 (32位二进制位)
float 单精度浮点型 占4字节空间 (32位二进制位)
double 双精度浮点型 占8字节的空间 (64位二进制位)
---------------------在64位平台--------------------------
char 字符类型 占1字节的空间 (8位二进制位)
short 短整型 占2字节的空间 (16位二进制位)
int 整型 占4字节的空间 (32位二进制位)
long 长整型 占8字节空间 (64位二进制位)
float 单精度浮点型 占4字节空间 (32位二进制位)
double 双精度浮点型 占8字节的空间 (64位二进制位)
sizeof 测量类型 的长度
#include<stdio.h> int main() { printf("sizeof(char)=%d\n",sizeof(char)); printf("sizeof(short)=%d\n",sizeof(short)); printf("sizeof(int)=%d\n",sizeof(int)); printf("sizeof(long)=%d\n",sizeof(long)); printf("sizeof(float)=%d\n",sizeof(float)); printf("sizeof(double)=%d\n",sizeof(double)); return 0; }
sizeof(char)=1 sizeof(short)=2 sizeof(int)=4 sizeof(long)=4 sizeof(float)=4 sizeof(double)=8
知识点2【unsigned 和 signed】
-
无符号数 unsigned
数据没有符号位, 自身的所有二进制位 都是***数据位***
比如:unsigned char 0000 0000 ~ 1111 1111
-
有符号数 signed 默认一般省略
二进制最高位为***符号位*** ,其它位 为 数据位
signed char xxxx xxxx (x:0 ~1)
最高位为1,表示负数,最高位为0,表示正数
负数 :1xxx xxxx 正数:0xxx xxxx
signed char 表示范围:1111 1111 ~ 1000 0000 ~ 0000 0000 ~ 0111 1111
案例:一个字节:-10 == 1000 1010
#include<stdio.h> int main() { //定义一个有符号int signed int num1 = 10;//num1有符号int //signed 默认是省略(推荐) int num2 = 10;//num2也是有符号int //unsigned 表示无符号数 不能省略 unsigned int num3 = 10; return 0; }
知识点3【结构体 struct 和 共用体 union】
-
srtuct 结构体 中的成员 拥有独立的空间
struct data1 { char a; short b; int c; }; a b c就是结构体data1中的内容;
-
union 共用体 中的成员 共享同一份空间
union data2 { char a; short b; int c; };
知识点4【enum 和 void】
-
enum 枚举 将变量要赋值的值一一列举出来。
enum BOOL{false, trule};
enum BOOL bool = false;
-
void 无类型 (重要)
不能用void 定义变量
知识点5【其他关键字】
-
auto自动类型, register寄存器变量,static静态变量,const只读
register int num; //尽量将num放入寄存器中(在高频使用时)
总结:
- 如果没有显示标明 register, 就类似int num,如果num被高频繁使用,系统也会放入寄存器中register int num;//显示的将num放入寄存器中。
-
寄存器的变量 不能 取地址
#include<stdio.h>
int main()
{
register int num = 10;
//%p输出地址
printf("%p\n", &num);//错误 不能对寄存器变量取地址
return 0;
}
+ sizeof 测类型大小
+ typedef为已有的类型 重新取个别名
```c
#include<stdio.h>
void test01()
{
register int num = 10;
//%p输出地址
}
//给已有的int类型娶个别名 INT32
typedef int INT32;
void test02()
{
int num1 = 10;
INT32 num2 = 20;
printf("num1 = %d\n", num1);
printf("num2 = %d\n", num2);
}
int main()
{
test02();
//while(1);由于结果一闪而过,故加阻塞代码。
return 0;
}
num1 = 10
num2 = 20
- volatile 防止编译器优化 强制访问内存操作
知识点6【常量和变量】
-
常量 值不能被修改 即具体值 (不可反过来说:值不能修改就是常量)
10 20 4.14 ‘a’ ‘num’
-
变量 系统根据变量的类型 开辟对应的空间 其值可以被修改。(用于存放临时数据或最终数据)
-
变量名 代表的是 空间的内容
操作变量 就是 对空间内容的操作
变量名的命名规则:由数值、字母、下划线组成但不能以数字开头。
-
特点:
变量在编译时为其分配相应的内存地址
可以通过名字和地址访问相应空间
知识点7【整型数据】
1、整型常量(按进制分)
-
十进制:以数字1 ~ 9 开头,如457 789
-
八进制:(0 ~ 7)以数字0开头,如0123
-
十六进制:(0 ~ 9, a ~ f )以0x开头,如0x1e
(八进制,十进制,十六进制 都是整型的输出形式)
void test03() { int num = 100; //十进制输出 输出 %d %u %ld %lu printf("十进制:num=%d\n", num); //八进制输出 输出 %o 以o 开头nzhixingshi printf("八进制:num=%#o\n", num);// #是为了输出时以进制形式输出 //十六进制输出 输出 %x 以ox开头 printf("十六进制:num=%#x\n", num); //不同进制 仅仅是数据的表现形式 不会修改数据数据本身 } int main() { test03(); return 0; }
十进制:num=100 八进制:num=0144 十六进制:num=0x64
2、整型变量(先定义后使用)
-
有/无符号短整型(un/signed) short(int) 2个字节
-
有/无符号基本整形(un/singed) int 4个字节
-
有/无符号长整型(un/singed) long(int) 4个字节
void test04() { //局部变量不初始化 内容随机 //int num; int data = 0; int num = 0; printf("num = %d\n", num);//读 取值 num = 100;//写 赋值 printf("num = %d\n", num); data = num;//num读 data写 printf("data = %d\n", data); //获取键盘输入 printf("请输入一个int数据:"); scanf("%d", &data); printf("data = %d\n", data); } int main() { test04(); return 0; }
num = 0 num = 100 data = 100 请输入一个int数据:200 data = 200 Press any key to continue
- 整型的输出形式
void test05() { int num1 = 0;//有符号int数据输出 printf("num1 = %d\n", num1); unsigned int num2 = 0;//在visual C++ 6.0中不支持这种写法,必须写在开头处。 //%u 无符号int数据输出 printf("num2 = %u\n", num2); long num3 = 0; //%ld 有符号long数据输出 printf("num3 = %ld\n", num3); unsigned long num4 = 0; //%lu 无符号long数据输出 printf("num4 = %lu\n", num4); short num5 = 0; //%hd 有符号short数据输出 printf("num5 = %hd\n", num5); unsigned short num6 = 0; //%hu 无符号short数据输出 printf("num6 = %hu\n", num6); } int main() { test05(); return 0;
-
}
```c
num1 = 0
num2 = 0
num3 = 0
num4 = 0
num5 = 0
num6 = 0
知识点8【实型数据】
3、实型常量(浮点数, 实数)
-
小数(定点)形式:由数值和小数点组成,必有小数点,部分不可同时省略。
例如:0.0、0.12、.56、5. 、6.0
-
指数形式:3.14e2
注意:e字母前必有数值,e 字母后必为整数
void test06() { //赋值语句 = 两边的类型 尽量保证一致 float f = 3.14f; // %f double f = 3.14; // %lf //不以 f 结尾的常量是double类型 printf("sizeof(3.14) = %d\n", sizeof(3.14)); //以 f 结尾的常量(如3.14f)是float类型 printf("sizeof(3.14f) = %d\n", sizeof(3.14f)); } int main() { test06(); return 0; }
sizeof(3.14) = 8 sizeof(3.14f) = 4
4、实型变量
- 单精度(float)和双精度(double)
- float型:占4字节,7位有效数字,指数-37到38
- double型:占8字节,16位有效数字,指数-307到308
知识点9【字符常量和变量】
-
直接常量:用单引号括起来的,如:‘a’、’b‘ 等
-
一个字符常量占一个字节存储空间,以ASCII码值来存储(数值),可以进行数值运算。
A -----> 65 B -----> 66
a -----> 97 b -----> 65
0 -----> 48 1 -----> 49
-
转义字符:以反斜杠“ \ ”开头,后跟一个或几个字符:\n换行
-
字符变量:用char定义,每个字符变量被分配到一个字节的内存空间,字符值以ASCII码的形式存放在变量的内存单元中;
char ch1 = ‘a’
void test07() { //%c 输出字符 //printf("%c\n", 'a'); //字符变量 //ch 存储的是 ‘a’的ASCII值 char ch = 'a'; printf("ch = %c\n", ch); //%d 输出的是字符的ASCII码值 printf("ch = %d\n", ch); //'a'单引号 表示的取 字符的ASCII //'a' == 97是完全等价 ch = 97; printf("ch = %c\n", ch); //%d 输出的字符的ASCII值 printf("ch = %d\n", ch); ch = ch+1; printf("ch = %c\n", ch); //%d 输出的字符的ASCII值 printf("ch = %d\n", ch); } int main() { test07(); return 0;
}
```c
ch = a
ch = 97
ch = a
ch = 97
ch = b
ch = 98
总结:字符在计算机存储的是ASCII值。'a’单引号表示取a得ASCII值。
char ch = 'a';
printf("%d\n", sizeof('a'));//4
printf("%d\n", sizeof(char));//1
总结:a = 97为整型常量。
-
获取键盘输入
void test08() { char ch; printf("请输入一个字符:\n"); //scanf中%c只能提取一个字符 //scanf("%c", &ch); ch = getchar();//获取一个字符,赋值给ch printf("ch = %c\n", ch); printf("ch = %d\n", ch); } int main() { test08(); return 0; }
请输入一个字符: a ch = a ch = 97
-
案例1
void test09() { char ch1, ch2; printf("请输入abc:"); //提取a ch1 = getchar(); getchar();//丢弃一个字符 ch2 = getchar(); printf("ch1 = %c\n", ch1); printf("ch2 = %c\n", ch2); } int main() { test09(); return 0; }
请输入abc:abc ch1 = a ch2 = c
-
案例2
void test10() { //'\n' 换行,'\t' tab //printf("##%c##\n", '\\');//两个\\输出一个\ char ch = '\0';//严格的格式 printf("A:%d\n", '0');//48 printf("B:%d\n", '\0');//0 printf("C:%d\n", 0);//0 printf("D:%d\n", "0");//字符0地址 } int main() { test10(); return 0; }
A:48 B:0 C:0 D:4337780// B 和 C 相同
知识点10【字符串常量】
-
由“ ”双引号括起来的字符序列,如"CHINA"、“C program”、"$12.5"等都是合法的字符串常量。
-
字符串常量与字符常量的不同:
'a’为字符常量,“a为字符串常量
每个字符串的结尾,编译器会自动的添加一个结束标志位‘\0’,即“a”包含两个字字符’a’和’\0’
void test11() { //%s 就是输出字符串 printf("%s\n", "Hello"); //系统会在字符串末尾自动添加一个结束字符“\0” printf("%d\n", sizeof("Hello")); } int main() { test11(); return 0;
‘h’ ‘e’ ‘l’ ‘l’ ‘o’ ‘\0’ void test11() { //%s 就是输出字符串 //''取的是字符的ASCII值 ""取的是字符串的首元素的地址 //%s 从字符串的首元素 逐个字符输出 遇到'\0'结束 printf("%s\n", "Hello"); //系统会在字符串末尾自动添加一个结束字符“\0” printf("%d\n", sizeof("Hello")); printf("%s\n", "hello world"); printf("%s\n", "hello\0world"); printf("##%s##\n", "\0hello\0world"); } int main() { test11(); return 0; }
Hello 6 hello world hello ####
-
格式化输出字符:
%d 十进制有符号整数 %u 十进制无符号整数
%x 以十六进制表示的整数 %o 以八进制表示的整数
%f float型浮点数 %lf double型的浮点数
%e 指数形式的浮点数 %s 字符串
%c 单个字符 %p 指针的值
-
特殊应用:
%3d %03d %-3d %5.2f
字符 说明 - 对齐方式,左对齐,若右对齐则省略(-) m 指定所占位 0 将空格以0填充 .n 保留n位小数 l 对整数以long 型输出 -
输出格式控制串:
- 格式说明:以%开头,例:%d,%f,%c
- 普通字符:原模原样输出
- 转义字符:以\开头
- 修饰符:% -、0、m、.n等
void test12() { printf("##############\n"); //%5d 表示占5个终端位宽 右对齐 printf("##%5d##\n", 123); //%-5d 表示占5个终端位宽 左对齐 printf("##%-5d##\n", 123); } int main() { test12(); return 0; }
############## ## 123## ##123 ##
知识点11【typedef】
-
为已有的类型重新 取个别名
- 用已有的类型 定义一个变量
- 用别名 替换 变量名
- 在整个表达式的前方加上typedef
案例1: int INT32 typedef int INT32; 案例2:给int arr[5] 取个别名 ARR typedef int ARR[5]; ARR arr;//arr就是一个拥有5个int元素的数组
《C和C指针》
《C陷阱和缺陷》
知识点12【数据类型转换】
数据有不同的类型,不同的类型数据之间进行混合运算时必然涉及到类型的转换问题。
-
自动转换遵循一定的规则,由编译系统自动完成。
-
自动转换的原则:
占用内存字节数少(值域小)的类型,向占用内存字节数多(值域大)的类型转换,以保证精度不降低。
-
转换方向:char、short ----->signed int ------>unsigned int----->long -------->double<-------float
-
由低至高
案例1
#include<stdio.h> void test01() { int data1 = -20; unsigned int data2 = 10; //有符号data1和无符号data2参加计算的时候 //会先将data1转换成无符号(-20的补码是很大的整数) //很大的数+10必然大于0 if(data1+data2) { printf(">0\n"); } else if(data1+data2 < 0) { printf("<0\n"); } } int main() { test01(); return 0; }
>0
案例2
void test02() { int data1 = 10; printf("%d\n",sizeof(data1+3.14)); } int main() { test02(); return 0; }
8
案例3
void test03() { char ch = 'a'; short data = 20; //由于char short自身字节数 过小 很容易溢出 //所以 只要char short参加运算 都会将自身转换成int printf("%d\n",sizeof(ch + ch)); printf("%d\n",sizeof(ch + data)); printf("%d\n",sizeof(data + data)); } int main() { test03(); return 0; }
4 4 4
-
-
强制转换
-
功能:把表达式的运算结果强制转换成所需的数据类型。
(类型说明符)(表达式)
-
例如:
(float)a; //把a的值转换为实型
(int)(x+y); //把x+y的结果值转换为整型
(int)x+y; //把a的值转换为整型 再和 Y的值相加
-
注意:
类型说明符必须加括号
void test04() { float x = 3.14f; int j = 0; //强制类型转换 只是临时的转换 在当前语句有效 在后面的语句中不会更改x的值 j = (int)x; printf("j = %d\nx = %f\n", j, x); } int main() { test04(); return 0; }
j = 3 x = 3.140000
无论是强制转换或者是自动转换,都只是为了本次运算的需要,而对变量数据长度进行的临时性转换,而不改变数据定义的类型。
-