变量、常量声明
变量的本质:一块存储区
int 整形; float浮点型; double双精度浮点型;
char字符型(1个字节也就是8位/8比特) 例子: char=‘A’ 字符型要记得单引号,char型在存储的本质也是int型 ASCC码
_Bool类型:1表示真true 0表示假false
定义常量(const)例: const int a; 常量值不可改变
定义常量 例: #define PI 3.14 该值也不可改变
打印, 转义字符
printf用来打印。
0x前缀表示16进制;
0(零)前缀表示8进制
十进制显示用%d;
十六进制显示%x;
八进制显示%o;
显示前缀可在%后加一个#;
显示char型%c;
显示int型 %d
显示float型%f
显示double型%f或者%lf
%e打印指数形式的浮点型
%s打印字符串
%p打印地址
特殊转义字符
。。。。
类型大小,字符串长度计算
sizeof() 打印相对的是%u或者%d
strlen()函数获取字符串长度(不包括\0) 使用时记得在写头文件 #
字符串和格式化输入,输出
字符串
字符串以 \0 为结尾,不用手打,系统自动填补
字符串就是u定义一个字符型数组 字符串赋值记得用 “ ”
使用scanf时只读取字符串第一个单词,因为scanf遇到空格、制表符、换行符就不在读取输入
格式化输入输出
printf修饰符
- 待打印项左对齐 例:%-20a
+ 待打印值显示正负号 例:%+20f
空格 若为正值则前面显示空格 若为负值则显示负值 例: % 20f
# 显示打印形式 例 %#x
0 前导0代替空格填补字段宽度 例 %010f
数字 最小字段宽度,如果太小则自动扩大 例 %4d
.数字 例 %.2f 保存小数点后两位
scanf
使用scanf要加地址符& 1.如scanf(“x=%d”,&i),此时需输入x=?
使用scanf读字符串不需要&
scanf如果读取成功返回1如果失败返回0,如果scanf中有两个参数就返回2
运算符、表达式和语句
运算符优先级
由高到底排序
()
±(正负) ++ - - 自加自减
*/ 乘除 还有%求模运算符
±加减
= <= > <
== 不等于!=
=等号 a+=203 也就是 a=a+(203) ; a-=20*3 同理; *= /= %= 都同理
如果记不住运算符优先级可多加括号
注:如果一个变量出现在一个函数的多个参数中,不要使用自加自减++ --;
如果一个变量多次出现在一个表达式中,不要使用自加或者自减;
复合语句(块)
{
}
花括号括起来的
带参数的函数
例:
#include <stdio.h>
void pound(int n); // ANSI function prototype declaration
int main(void)
{
int times = 5;
char ch = '!'; // ASCII code is 33
float f = 6.0f;
pound(times); // int argument
pound(ch); // same as pound((int)ch);
pound(f); // same as pound((int)f);
return 0;
}
void pound(int n) // ANSI-style function header
{ // says takes one int argument
while (n-- > 0)
printf("#");
printf("\n");
}
- 该例子中 变量n是形式参数 调用pound(times)就是把times=5赋值给n 称之为实参
- 数组做函数的形参有什么好处? 答:可以跨函数使用存储区
- 跨函数使用存储区方法:①使用数组做函数形参 ② 使用指针做函数形参 ③ 使用静态局部变量+指针类型返回值 注: 实现跨函数使用存储区均需通过指针才能实现
例2
#include<stdio.h>
int a, b;
void fun()
{
a=100; b=200;
}
int main()
{
int a=5, b=7;
fun();
printf("%d %d\n", a, b);
return 0;
}
该例中,没有调用到fun()函数,如果想调用可以改为指针的形式,只有对存储单元进行操作才能改变该存储单元里的值。
循环
while循环
while(判断循环条件)
{
}
如果没有花括号,从while开始执行直到第一个 分号;结束。
注意 == 和= 不一样 前者是相等运算符 后者是赋值运算符,我们常把== 写成= 为了便于编译器捕获错误可把数字写在右边 也就是比如 5canoes 而不是canoes5
可以巧妙用scanf的返回值作为判断条件 成功读取返回1 读取失败返回0
例
#include <stdio.h>
int main(void)
{
long num;
long sum = 0L; /* initialize sum to zero */
int status;
printf("Please enter an integer to be summed ");
printf("(q to quit): ");
status = scanf("%ld", &num);
while (status == 1) /* == means "is equal to" */
{
sum = sum + num;
printf("Please enter next integer (q to quit): ");
status = scanf("%ld", &num);
}
printf("Those integers sum to %ld.\n", sum);
return 0;
}
真假判断
除了0都是真
for循环
例l
for(n=0;n<10;n++)
{
}
其中n=0只执行一次, ()括号里的写法很灵活 可以多种多样例for(;n<10;n++) for(;;n++)等等
逗号运算符
从左往右计算
两个属性
- 都号左侧的值在运行到逗号右侧之前就执行完毕
- 逗号表达式的值是右侧项的值 例子
x=(5,18) 也就是x=18;
do while循环
for和while都是入口条件循环,也就是在循环前先检查循环条件是否满足,若不满足,一次都不循环。 而do while循环是出口条件循环,也就是先就行循环在检查循环条件,这就保证了至少进行一次循环
do while循环多用于输入密码的时候
例
/* do while循环 */
#include<stdio.h>
int main(void)
{
char name ='c';
char s_name;
do
{
printf("name is ? \n");
scanf("%c",&s_name);
} while(s_name != name);
printf("congratulation! \n");
return 0;
}
如何选择循环
一般用入口条件的循环多业就是while和for循环,至于选择哪个,视情况而定,两个循环都可以做到相同的事。 但是建议用到初始化和更新变量时用for循环。 如果只是判断循环条件是否满足就用while循环。
循环嵌套
例子
/* rows1.c -- uses nested loops */
#include <stdio.h>
#define ROWS 6
#define CHARS 10
int main(void)
{
int row;
char ch;
for (row = 0; row < ROWS; row++) /* line 10 */
{
for (ch = 'A'; ch < ('A' + CHARS); ch++) /* line 12 */
printf("%c", ch);
printf("\n");
}
return 0;
}
C语言是一行一行挨着执行的。也就是说所有嵌套循环中的内层循环在每次外层循环迭代(更新)时都执行完所有循环。
一般使用嵌套循环都是为了显示列或者行。
嵌套变化
内层循环打印的字符要取决于外层的循环迭代次数 例
#include <stdio.h>
int main(void)
{
const int ROWS = 6;
const int CHARS = 6;
int row;
char ch;
for (row = 0; row < ROWS; row++)
{
for (ch = ('A' + row); ch < ('A' + CHARS); ch++)
printf("%c", ch);
printf("\n");
}
return 0;
}
数组
- 数组里的数必须类型相同如 int num[20];意思时由20个元素构成的数组,这二十个元素全部都是int型
- **注:**注意数组溢出的问题 如上面这个数组不赋值不能写成num[20]或者更大,编译器不会报错,但程序会出现问题。 数组元素是从0开始计数的,在存储空间中一个挨着一个排列的。上面的就是从0——19二十个元素。
- 假如给以上数组的第五个元素赋值,可写为num[4]=10;
- 字符串本质就是字符数组,但是字符数组不是字符串,结尾有 \0是字符串,如果没有就是字符数组。
在for循环中使用数组
例
#include<stdio.h>
int main(void)
{
int result[10];
int a;
int sum =0;
printf("Please enter 10 student result");
for(a=0;a<10;a++)
{
scanf("%d",&result[a]);
}
for(a=0;a<10;a++)
printf("%5d ",result[a]);
printf("\n");
for(a=0;a<10;a++)
sum += result[a];
printf("sum is %d",sum);
return 0;
}
分支和跳转
if else 语句
**注:**if和else之间只允许有一天语句(简单语句或复合语句,也就是{}大括号括起来的)
#include<stdio.h>
int main(void)
{
int num;
printf("Please enter the number (q to quit): \n");
while(scanf("%d",&num)==1)
{
if(num>0&&num<10)
{
printf("This number is bigger then 0 samll then 10 \n");
}
else if(num>10&&num<20)
{
printf("This number is bigger then 10 small then20 \n");
}
else if(num>20&&num<30)
{
printf("This number is bigger then 20 small then30 \n");
}
else
{
printf("handsome young chap \n");
}
}
}
条件运算符 ?:
getchar() putchar()函数
- getchar() putchar()函数只能处理字符
- ch = getchar(); 也就相当于 scanf("%c",ch)
- putchar(ch) 也就相当于 printf("%c",ch)
逻辑运算符
- &&与
- || 或
- !非
- !非得优先级只比括号低
- &&运算符的优先级比||运算符高
注: 记不住优先级就多用括号
条件运算符 ?: (c语言中唯一一个三元运算符)
例:
x=(y<0)? -y : y;
意思是如果y<0那么x=-y,否则x=y
循环辅助 continue 和break
continue
3种循环都可以用continue;
执行到continue时会跳过continue以下的循环,开始一轮新的循环,如果continue在嵌套循环内,只影响离他最近的循环,也就是内层循环。
例:
/* 就算学生的最高分最低分以及平均分*/
#include <stdio.h>
int main(void)
{
const float MIN = 0.0f;
const float MAX = 100.0f;
float score;
float total = 0.0f;
int n = 0;
float min = MAX;
float max = MIN;
printf("Enter the first score (q to quit): ");
while (scanf("%f", &score) == 1)
{
if (score < MIN || score > MAX)
{
printf("%0.1f is an invalid value. Try again: ",
score);
continue; // jumps to while loop test condition
}
printf("Accepting %0.1f:\n", score);
min = (score < min)? score: min;
max = (score > max)? score: max;
total += score;
n++;
printf("Enter next score (q to quit): ");
}
if (n > 0)
{
printf("Average of %d scores is %0.1f.\n", n, total / n);
printf("Low = %0.1f, high = %0.1f\n", min, max);
}
else
printf("No valid scores were entered.\n");
return 0;
}
continue只能用于循环中
break语句
跳出循环,执行循环后面的第一条语句。
如果是嵌套循环就跳出内层循环也就是跳出离他最近的一个循环。
多重选择 switch case 和break
例
#include<stdio.h>
int main(void)
{
char ch;
printf("Please a letter ");
scanf("%c",&ch);
switch (ch)
{
case 'a':
printf("handsome young chap \n");
break;
case 'b':
printf("beautiful gir \n");
break;
case 'c':
printf("people \n");
break;
default:
printf("None \n");
break;
}
return 0;
}
注意:如果某个case后没有break将会执行该case以下的所有语句,直到遇到break为之。
default意思是,以上条件都不满足,就执行该语句
switch圆括号里必须是一个整数值 ;
case标签必须是整数类型的常量或整形常量表达式,不能用变量做case标签。
goto语句
C语言中不提倡用goto语句,只在一种情况下使用,出现问题时从一组循环 嵌套中跳出
只读每行的首字符,丢弃其他多余的(包括换行)
while(getchar() !=’ \n ’ )
continue;
字符输入/输出和输入验证
缓冲区
使用缓冲区更快
缓冲区分为完全缓冲区(缓冲区填满才刷新缓冲区)和行缓冲区(出现换行符时刷新缓冲区)
文件结尾
- C语言把输入输出设备视为存储设备上的普通文件,尤其是把键盘和显示u设备视为每个C程序自动打开的文件 C语言中用getchar和scanf读取文件检测到文件结尾时将返回一个特殊值,也就是EOF(EOF是一个值标志着检测到到文件结尾,并不是在文件中找到的的符号。EOF已经在stdio.h中定义过,所以不必关心他的值)
- 使用键盘输入要设法输入EOF,只需在一行开始处按下Ctrl+z就会解释为文件结尾信号
重定向和文件
重定向:改变文件输入或者输出的来源。
- Linux中重定向输入 ./可执行文件名 < 输入来源
- Linux中重定向输出 ./可执行文件名 >输出文件名
- Linux中组合重定向 ) ./可执行文件名 >输出文件名 <输入文件名
./可执行文件名 <输入文件名 >输出文件名
这两个意思都是,把输入文件输出到输出文件里,命令与重定向运算符顺序无关
注:输入输出文件名不能重名
重定向必须是一个可执行文件和一个数据文件
函数
形式参数
例:
#include <stdio.h>
void pound(int n); // ANSI function prototype declaration
int main(void)
{
int times = 5;
char ch = '!'; // ASCII code is 33
float f = 6.0f;
pound(times); // int argument
pound(ch); // same as pound((int)ch);
pound(f); // same as pound((int)f);
return 0;
}
void pound(int n) // ANSI-style function header
{ // says takes one int argument
while (n-- > 0)
printf("#");
printf("\n");
}
- 该例子中 变量n是形式参数 调用pound(times)就是把times=5赋值给n 称之为实参
- 形式参数是局部变量
- 数组做函数的形参有什么好处? 答:可以跨函数使用存储区
- 跨函数使用存储区方法:①使用数组做函数形参 ② 使用指针做函数形参 ③ 使用静态局部变量+指针类型返回值 注: 实现跨函数使用存储区均需通过指针才能实现
- 形式参数定义形式
① void dibt(intx,y,z) //无效,错误
②void dibt(int x,int y,int z) //有效,正确 - 形参只有在被赋值的时候才开辟存储单元
- 如果函数不需要参数,就在括号里明确写上(void)
例2
#include<stdio.h>
int a, b;
void fun()
{
a=100; b=200;
}
int main()
{
int a=5, b=7;
fun();
printf("%d %d\n", a, b);
return 0;
}
该例中,没有调用到fun()函数,如果想调用可以改为指针的形式,只有对存储单元进行操作才能改变该存储单元里的值。
使用return从函数中返回值
例
/* lesser.c -- finds the lesser of two evils */
#include <stdio.h>
int imin(int, int);
int main(void)
{
int evil1, evil2;
printf("Enter a pair of integers (q to quit):\n");
while (scanf("%d %d", &evil1, &evil2) == 2)
{
printf("The lesser of %d and %d is %d.\n",
evil1, evil2, imin(evil1,evil2));
printf("Enter a pair of integers (q to quit):\n");
}
printf("Bye.\n");
return 0;
}
int imin(int n,int m)
{
int min;
if (n < m)
min = n;
else
min = m;
return min;
}
注:返回值类型要与函数类型相匹配,比如int,char等等,无返回值的函数声明为void类型
递归(了解)
C允许函数调用他自己,这种调用称为递归
例
/* recur.c -- recursion illustration */
#include <stdio.h>
void up_and_down(int);
int main(void)
{
up_and_down(1);
return 0;
}
void up_and_down(int n)
{
printf("Level %d: n location %p\n", n, &n); // 1
if (n < 4)
up_and_down(n+1);
printf("LEVEL %d: n location %p\n", n, &n); // 2
}
- 每级函数都有自己的变量,也就是第一级的n和第二级的n不一样
- 每次函数调用后都会返回一次值,当函数执行完毕后,控制权将被传回上一级递归,程序必须按顺序逐级返回递归
- 递归函数中位于递归调用之前的语句,均按被调函数的顺序执行
- 递归函数中位于递归调用之后的语句,均按被调函数相反顺序执行
编译多元代码文件的程序
- 把函数原型和已定义的字符常量放在头文件中是一个很好的编程习惯,也就是写在(.h)文件里
- <stdio.h>表示在库文件中找 “stdio.h”表示自己写的头文件
&运算符与指针
函数传递参数,不改变参数原本的值
若想改变参数本身的值,可以用指针的形式,也就是传递指针,因为指针是对存储单元进行操作。
例
/* swap1.c -- first attempt at a swapping function */
#include <stdio.h>
void interchange(int u, int v); /* declare function */
int main(void)
{
int x = 5, y = 10;
printf("Originally x = %d and y = %d.\n", x , y);
interchange(x, y);
printf("Now x = %d and y = %d.\n", x, y);
return 0;
}
void interchange(int u, int v) /* define function */
{
int temp;
temp = u;
u = v;
v = temp;
}
使用指针形式
#include <stdio.h>
void interchange(int* u, int* v); /* declare function */
int main(void)
{
int x = 5, y = 10;
int* p_x=&x;
int* p_y=&y;
printf("Originally x = %d and y = %d.\n", x , y);
interchange(p_x,p_y);
printf("Now x = %d and y = %d.\n", x, y);
return 0;
}
void interchange(int* u, int* v) /* define function */
{
int temp;
temp = *u;
*u = *v;
*v = temp;
}
数组和指针
数组
- 数组里的数必须类型相同如 int num[20];意思时由20个元素构成的数组,这二十个元素全部都是int型
- **注:**注意数组溢出的问题 如上面这个数组不赋值不能写成num[20]或者更大,编译器不会报错,但程序会出现问题。 数组元素是从0开始计数的,在存储空间中一个挨着一个排列的。上面的就是从0——19二十个元素。
- 假如给以上数组的第五个元素赋值,可写为num[4]=10;
- 字符串本质就是字符数组,但是字符数组不是字符串,结尾有 \0是字符串,如果没有就是字符数组。
- 数组名是数组首元素的地址
多维数组
二维数组可以把他看成几行几列的一个矩阵
例: int num [5][8] 是一个5行8列的二维数组
一般用循环嵌套处理二维数组。
指针
- 在C中,指针加一是指增加一个存储单元,对数组而言,地址会增加到下一个元素的地址。
- 通常,求差的两个指针指向同一个数组的不同元素,通过计算求出两元素的距离,差值的单位与数组的单位相同;例如数组是 int ar[] 则求差的单位也是int型,加入求差后等于2也就是2个int型,也就是8字节。