C语言基础语法(2遍)
c#title: C语言基础
6.创建并运行第一个C程序
集成开发环境(IDE)
编译器/C语言中的指令-机器指令
VC6版本
安装虚拟机+VC6建议学习
同学帮助安装
编写C程序
1.创建项目,选择win32控制台项目(Win32 console Application)
文件-新建-Win32 console Application(项目名字为时间的顺序2020_06_16)
2.添加文件
文件-新建-C++ Source File-Main.cpp
3.生成项目(编译):*.exe
#include <stdio.h>
int main()
{printf("Hello,World!\n");getchar();return 0;
}
F7(出现00error为程序已经创建成功)
2020_06_15.exe - 0 error(s), 0 warning(s)
4.运行项目
F5
cpp为C++文件
shift+F 程序结束
debug版本(调试版本)
release版本(发布版本) 编译器会优化掉一部分无用代码
7.内存与变量
内存的使用
内存的单位是字节(Byte) 每个字节占8个位(bit)
每个运行中的程序(进程)都有4G内存
内存的编号就是地址
内存不是内存条,是空头支票
变量类型
变量就是内存
变量类型就是告诉系统(编译器)我需要的内存有多大
变量名告诉系统(编译器)我需要的内存在哪里,变量名是地址的别名
值是写到内存里的数据
变量类型 变量名称 = 值;
十六进制为"%x"
十进制为"%d"
数据到底存在哪里?
取地址符号==&==
//变量类型 变量名(就是内存编号) 变量值
char x = 10;
short y = 100;
int z = 1000;
//打印内存中的数值
printf("值为:%d-%d-%d\n",x,y,z);
printf("值为:%x-%x-%x\n",x,y,z);
&符号可以帮助我们获取指定的变量的地址:
printf("变量内容为:%d-%d-%d\n",x,y,z);printf("变量地址为:%p-%p-%p\n",&x,&y,&z)
溢出范围
溢出的右移,舍弃
char //0 - 0xFF
short //0 - 0xFFFF
int //0 - 0xFFFFFFFF
浮点型变量的使用
每种类型的变量,存储的数据都是有范围,超过这个范围的数据,将会被计算机丢弃,如:
float x = 100.12f; //4字节,float后面跟f
double y = 100.1234;//8字节(范围很大)printf("%f %lf\n",x,y);//%f与%lf分别是存储float与double的形式
printf("%.2f %.4lf\n",x,y);//显示小数点后几位,.2位或者.4位定义输出的小数点位数
总结
变量类型 | 变量宽度(字节byte)16进制 | 存储范围 |
---|---|---|
char | 1 | -128~127 |
short | 2 | -32768~32767 |
int | 4 | -2147483648~2147483747 |
float | 4(精度:整数+小数6-7) | -3.4·1038~3.4·1038 |
double | 8(15-16) | -1.7·10308~1.7·10308 |
课后练习
1.如何理解内存
一个内存为一个字节
2.如何理解内存编号
内存编号就是内存地址,别名就是变量名
3.分别使用char、short、int、float、double申请内存,并用 printf 正确输出对应内容和地址
#include<stdio.h>
char a = 10;
short b = 100;
int c = 100;
float e = 50.12f;
double f = 3432.3423;int main()
{printf("%d %d %d %f %lf\n", a,b,c,e,f);printf("%d %d %d %.2f %.4f\n",a,b,c,e,f);printf("%x %x %x %x %x\n",a,b,c,e,f);printf("%p %p %p %p %p\n",a,b,c,e,f);getchar();return 0;
}
3.为什么要使用变量
回顾
char 一个字节、
short 四个内存
int 八个字节
使用&地址符号,获得当前地址的内存
编译器替我们是申请
内存太多,使用编号代替,一个内存的编号就是地址,一个地址里面代表一个字节,一个字节就是八个0或者1
#include<stdio.h>
//变量类型 变量名字 值
int main()
{char x = 10;//可以放进程序里面可以放到程序外面,但是如果放进程序里面,仅仅是当前程序使用,其他程序无法使用printf("%d",x);getchar();return 0;
}
放到函数里面必须有一个明确的初始值
放到函数外面称为全局变量
为什么要使用变量
变量本身是一个内存
变量的本质是容器,里面可以存储任意类型的数据
实例
可以根据用户输入圆的半径,计算出圆的面积。
#include <stdio.h>
#define PI 3.14//定义常量int main()
{double r;double s;scanf("%lf",&r);//变量的地址在哪里,控制台就会读入一个数,放入r的地址。s = PI*r*r;printf("%lf \n",r);printf("%.4lf\n",s);getchar();getchar();
}
常量是一个数,不会变化
用变量是为了临时储存数据
内存就是变量
变量命名规则
- 只能由字符,数字,下划线
- 第一个符号不能是数字
- 变量名不能是关键字
小端存储模式
#include <stdio.h>char a = 0x12;//一个字节
short b = 0x1234;.//两个字节
int c = 0x12345678;//四个字节
printf("%p,%p,%p \n",&x,&y,&z)
大端小端针对的是数据超过1个字节的存储
小端模式:数据低位在内存地址编号低位,数据高位在高位
大端模式:数据高位在内存地址编号低位,数据高位在低位
程序在断点才可以看memory
float使用二进制规范存储,将小数点变为二进制IEEE规则
#include <stdio.h>int main()
{char x = 0x12;short y = 0x1234;int z = 0x12345678;//12 34 56 78//0019FF28-0019FF24//78 56 34 12printf("%p,%p,%p\n,"&x,&y,&z);getchar();//断点在getchar不能看memoryreturn 0;
}
使用小手选择断点调试
getchar()因为程序一直在运行,所以无法进行调试,需要删除掉
选择断点-把要看的变量名输入到address输入框中-查看存储的内存地址
原码反码补码
回顾
如何让程序运行到某阶段的存储下来
浮点型有自己的存储规范,课堂上不涉及
当存储的12时是12,负数的时候存储的是EE
原码反码补码
原码:最高位为符号位,其余各位为数据本身的绝对值
0X12 = 0001 0010;//正数,最高位0正,最高位1为负
反码:
正数:反码与原码相同
负数:符号位为1,其余位取反
补码:
正数:补码与原码相同
负数:符号位为1,其余位对原码取反加1
0x12 0001 0010
原码:0001 0010
反码:0001 0010
补码:0001 0010
-0x12 EE
原码:1001 0010//符号位为1,负数
反码:1110 1101//符号位为1,取反
补码:1110 1110 //末位+1
E E
计算机存储整数的时候存储补码
有符号数与无符号数
谁能告诉我下面的1代码表示什么?
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
#include <stdio.h>int main()
{int x = 0xFFFFFFFF;prinf("%u,%d\n",x,x);return 0;
}
%u:无符号数的输出标记
%d:有符号数的输出标记
有符号数与无符号数在存入内存的时候是相同的,比如
int a = -1;
unsigned a = -1;
//此两者在存储时是相同的,存入内存的数值都是
//FFFF FFFF
#include <stdio.h>int main()
{unsigned char x = 0xFF;//1111 1111unsigned int y = x;//0000 0000 1111 1111int y = x;//1111 1111 1111 1111printf("%p,%p\n",x,y);return 0;
}
%x:十六进制输出标记
%p:类似于地址,全部位输出标记
有符号数与无符号数区别
- 拓展的时候有差异
#include <stdio.h>int main()
{char x = 0xFF;printf("%x\n",x);int y = x;printf("%x\n",y);unsigned char a = 0xFF;printf("%x\n",a);unsigned int b = a;printf("%x\n",b);getchar();return 0;
}
计算结果如下:
ffffff ff//拓展成四个字节打印
fffff ff//有符号数,使用符号位进行补位
ff//无符号数
ff//无符号数
- 比较的时候有差异
#include <stdio.h>int main()
{unsigned int a = -1;if (a>1){printf("%p",a);}return 0;
}
总结
- 无论有符号数与无符号数,内存存储的方式是一样的,补码
- 有符号数与无符号数在使用的时候,主要的区别是:
<1>拓展的时候
<2>运算的时候
只有整数才有有符号与无符号之分
浮点数另算
字符与字符串
单引号==’ '==只是单个字符
ACSII表
A-65
a-97
putchar()
只能打印一个字符,给他任何数字都会进行查表,然后输出表的对应值
转义字符 \a = 7, \n = 10
#include <stdio.h>void main()
{char buffer[6] = {'H','e','l','l','o','!'};printf("%s",buffer);
}
结果:因为没有0结束,会出现一些别的打印结果
所谓字符串是以数组的形式来表示的
输出打印字符串需要见到0才能停止,当数组扩大,会自动补0
一般情况下不用指明长度,编译器会计算长度,自动补0。
字符串的来由
- 字符串其实是一对字符组成的
- 字符就是ASCII码对应得到的
- ASCII码对照的是十进制数
- 存入的是十进制数的二进制数
中文字符
英文字符查表,中文如何操作的呢?
中文也有值,每个中文字有两个字节的占格
计算机发明之后及后面的很长一段时间,只用应用于美国及一些西方国家
我们专家把那些127之后的奇异符号们(EASCII)取消掉
规定两个大于127的数定义为汉字,字符等,全角
GB2312
Win32-unicode本质就是查表
8.数组
为什么要使用数组
数组是连续申请一些内存供应使用
数组的地址是第一个数组的地址
如果我们要存储多人的年龄
能否让编译器分配多一点的int
void main()
{int age[20];//向编译器申请了40个字节的空间
}
数组的初始化
整数是小端存储
int age[20] = {0};//初始化全部为0
- 定义时是不初始化,如:
int age[20];
- 定义时直接初始化,如:
int age[10] = {1,2,3,4,5,6,7,8,9,10}
- 定义时部分初始化,如:
int age[10] = {1,2,3,4,5};
数组的使用
越界/当你取数组中的数值时,假设数组中有10个值,age[10],值已经越界。
通过下标访问数组
其他类型的数组
char arr[10];
short arr[20];
int arr[20];
使用watch来查看你申请得到的数组内的值
查看-调试-watch-右边输入名称
训练
- 创建一个长度为10的整型数组,并为这个数组赋值(值是下标的2倍);
- 将上题中数组的第一个元素与最后一个元素的值交换。
#include <stdio.h>
void main()
{int arr[10]={0,3,4,6,8,10,12,14,16,18};int a;printf("交换前:%d %d\n",arr[0],arr[9]);a = arr[0];arr[0] = arr[9];arr[9] = a;printf("交换后:%d %d\n",arr[0],arr[9]);
}
二维数组
解决问题
name | math | chinese | english |
---|---|---|---|
小明 | 89 | 67 | 67 |
小黄 | 73 | 42 | 65 |
小红 | 56 | 56 | 47 |
47 | 78 |
int score[12] = {...}
//寻找
第x个同学,第y门课
score[x*3+y]
直接告诉编译器几人几科
int score[3][2] = {...};//二维数组
int score[0][0];//第一人第一科
int score[1][1];//第二人第二科
int score[2][2];//第三人第三科
二维数组与数组在存储方式上是相同的,不同工作主要是由编译器运作,二维数组就是一维数组
修改的情况下直接修改可以
二维数组的初始化形式
int arr[3][4]={1,2,3,4,5,6,7,8,9,7,6,5
}int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,7,6,5}
}int arr[3][4]={{1,2},{5},{9}
}int arr[][4]={1,2,3,4,5,6,7,8,9,10,11,12
}//自动分配少数补0
第二个维度必须指定
初始化写{0}即可
多维数组
多维数组
int arr[3][4][5] ={{{1,2,3},{4,5,6},{7,8,9},{10,11,12,14}},{{10,20,30},{40,50,60},{70,80,90},{110,120,130}},{{11,21,31},{41,51,61},{71,81,91},{111,121,131}}
}
第几个组(x):0,1,2
第几个人(y):0,1,2,3
第几门课(z):0,1,2
寻找
2-2-2;
arr[1*3*4+1*3+1] = arr[1][1][1];
总结
没有二维数组或者多维数组,本质都是一维数组
9.运算符与表达式
算术运算符
什么是运算符?什么是表达式?
表达式是运算符与运算与常量的之间的关系
x+y x-y (x+y)(x-y) 表达式都是值
==%%==使用两个才能显示
//++ – 单目运算符
int x = 10;
++x;
printf("%d \n",x);//输出11
printf("%d \n",x++)//先参与运算,再自加
运算符优先级别==()==
()具有最高优先级
算术表达式的结果类型
char x = 1;
short y = 2;
int z = 3;
printf("%d\n",sizeof(x+y));
printf("%d\n",sizeof(x+z));//当与int运算时会升级
void main()
{int n = 1;unsigned int = 0xffffffff;if((m+n)>0){printf("表达式类型为unsigned: %d\n");}
//有符号数与无符号数进行运算,结果是无符号数
}
位运算
什么是位运算
- 程序中所有数在计算机内存中都是二进制的形式存储的
- 位运算就是直接对整数在内存中的二进制位进行操作
位运算能做什么
计算机底层相关领域:
加密解密 安全 反病毒 反外挂
位运算能够精确的对某一个位进行操作
位运算有哪些
计算方式 | 计算过程 |
---|---|
按位与 & | 全部是1取1 |
按位或 | | 有1取1 |
按位异或 ^ | 不同为1,相同为0 |
按位取反 ~ | 取反 |
左移 移位运算 << | |
右移 移位运算 >> | 无符号数补0,有符号数补符号位 |
位运算举例
如何将二进制数中的某一个位置修改为1? //3位
x|4//修改某一个位,通过与运算1010 10100000 0100---------1010 1110
如何将二进制数中的某一位置修改为0; //3位
x&FB1010 11101111 1011---------1010 1010
练习
1. 2*8的最高效的实现方式.
2 | 0000 0010 |
---|---|
2*8 | 0001 0000 |
//右进位进三位
2. 如何通过位运算判断一个数是奇数还是偶数?
3 | 0000 0011 |
---|---|
按位或 | | 0000 0001 |
有1取1 | 0000 0011 |
//相同为奇数,不同为偶数
3. 如何读取二进制数中的某一位的值?
16 | 0001 0000 |
---|---|
16>>(n-1)&1 | 0000 0001 |
取n位值(x>>(n-1))&1
4. 如何设置二进制数中的某一位的值?
n修改第n位的值为1 | 0000 0000 |
---|---|
按位或| (2n-1) | 0001 0000 |
1<<n-1 | 0001 0000 |
修改第n位的值为0 | 0001 0000 |
---|---|
按位与 &((2字节长度-1)-2n-1) | 1110 1111 |
0000 0000 |
设置相反x^(1<<n-1)^
5. 设 int a = 2; int b = 5; 使用位运算,交换两个变量的值,并打印。
2 | 0000 0010 |
---|---|
5 | 0000 0101 |
自己的见解
#include<stdio.h>
int a = 2;
int b = 5;
void main()
{a=(a << 1)|1;b=b >> 1;printf("%d %d",a,b);
}
王者见解
#include<stdio.h>
int a = 2, b= 5;
void main()
{a = a^b;b = b^a;a = a^b;printf("%d%d",a,b);
}
6.使用位运算 获取 int 类型的最大值和最小值,并打印
#include<stdio.h>
void main()
{int a;a=0;printf("%x",~i);
}
运算符种类
赋值运算符
赋值是一个动作,表达式是一个数
x = x + 8;
x += 8
标准运算
拓展赋值
关系运算符
- 什么是真(非0),假为0
- 关系运算符返回结果为真假
关系运算符用于比较两者的关系
关系运算符也是双目运算符
void main()
{int x = 1;int y = 2;printf("%d,%d", x>y);/假,为0
}
三目运算符
也叫条件运算符
表达式1 ? 表达式2 :表达式3
当表达式1为真时 整个表达式的结果为表达式2
当表达式2为真时 整个表达式的结果为表达式3
void main()
{int x = 1;int y = 2;int z = 3;int k = x=y?y:z;//三目运算符printf("%d",k);
}
逻辑运算符
&&逻辑与运算,可以理解成"并且"
说明:
- 当表达式1为真时,并且表达式2为真时,整个表达式的结果为真,否则为假
- 短路特征,当表达式1为假时时候,后面的表达式将不再执行
逻辑或||,可以理解成“或者”
- 当表达式1为真或者表达式2为真时,整个表达式的结果为真,否则为假
- 短路特征,当表达式1为真的时候,后面的表达式将不再执行
非!
加在任何表达式的前面,改变表达式的值
练习
int x =4; int y = 7; int z = 3;用三目表达式求出三个变量中的最大值
自己迂腐之见
#include<stdio.h>
int x;
int y;
int z;
void main()
{scanf("%d %d %d",&x,&y,&z);int a = x>y?x:y;int b = x>z?x:z;int c = y>z?y:z;if(a==x&&b==x)printf("最大值为x:%d",x);else if(a==y&&c==y)printf("最大值为y:%d",y);elseprintf("最大值为z:%d",z);getchar();getchar();
}
王者级别
#include<stdio.h>
int x=3,y=4,z=7;
void main()
{printf("%d",x>y?(x>z?x:z):(y>z?y:z));
}
不运行程序,说出打印结果,为什么?
#include<stdio.h>
void main()
{int x;printf("%d\n",x = 60);printf("%d\n",x ==60);
}
60//表达式为值
1//有数为真为1
不运行程序,说出结果,并解释.
#include<stdio.h>
void main()
{int a=1,b=2,c=0,d=0,e;e= (d = b > a) || (c = a < b);printf("%d %d %d\n", e,c,d);
}
1
0
1//b>a的优先级比较高
将上题中的 e= (d = b > a) || (c = a < b); 改为 e= (d = b > a) && (c = a < b); 说出结果 并解释
1
1
1
10.C 语言流程控制
人生选择坚持的人,虽然不一定会成功,但是一定无限接近于成功
流程控制
if
如果
分支语句的本质是选择
循环语句的本质是重复执行(重点是终止条件)
常见循环
while:先判断,后循环,不达目的不罢休、
实例
打印99乘法表
#include<stdio.h>
//核心就是i是从1-9,j每次都从1开始到与i同等大小为止
int main(void)
{int i = 1;int j;while (i<10){j = 1;while(j<=i){printf("%d*%d=%d ",i,j,i*j);j++;}i++;printf("\n");}
}
do while:先执行,后判断
实例
计算1+2+3+…+(n-2)+(n-1)+n的值
int sum = 0;
int i = 1;
do
{sum = sum + i;i++;
}while(i>n)
for 循环:指定生效次数
有1,2,3,4四个数字,能组成多少互不相同且无重复的三位数?都是多少?
#include<stdio.h>
int main(void)
{int cont = 0;for(int i = 1; i<5; i++){for(int j = 1; j<5;j++){for(int k = 1; k < 5; k++)if((i != j)&&(i != k)&&(j != k)){printf("%d%d%d\n",i,j,k);cont++} }}print("共计%d",cont);return 0;
}
if 语句
1.如何控制程序的流程?
void main()
{int x = 56;if(x>=68)printf();elseprintf();
}
2.if语句
if(表达式x)//表达式可以是任何类型语句y;//当表达式x为真(非零)时,执行语句y
一行里可以写很多语句
分支语句/无论条件如何,只有一个分支运行,只走一条线
可以精简代码
void main()
{int x = 80;if(x<68){printf("不及格\n");}else if(x<70)//范围可以精简{printf();}else if(x<80){printf();}else{printf();}
}
可以嵌套
练习
1.输入三个整数x,y,z,请把这三个数由小到大输出。
#include<stdio.h>
int x,y,z;void swap(int *a, int *b)
{int temp;temp = *a; *a = *b;*b = temp;
}
int main()
{scanf("%d %d %d",&x,&y,&z);int temp;//精妙三者排序if(x>y)swap(&x,&y);if(x>z)swap(&x,&z);if(y>z)swap(&y,&z);printf("%d %d %d",x,y,z);getchar();getchar();return 0;
}
2.判断某一年是否是闰年。
#include <stdio.h>int x;
void main()
{scanf("%d",&x);if(x%4==0)printf("%d年是闰年",x);elseprintf("%d年不是闰年",x);
}
3.一个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同。(精)
#include<stdio.h>
int a;
void main()
{scanf("%d",&a);if((a/10000)%10==(a%10)&&(a/10)%10==(a/1000)%10)printf("是回文数\n");elseprintf("不是回文数\n")
}
4.从键盘接收一个字符,如果是小写字母,就输出对应的大写字母。如果是大写字母,输出对应的小写字母。
#include<stdio.h>
void main()
{char c;c = getchar();//scang("%d",c)if(c < 65)printf("请重新输入");else if(c < 91)printf("%c",c+32);else if(c<123)printf("%c",c-32);elseprintf("请重新输入");getchar();getchar();
}
5.不运行程序,说出下面程序执行的结果
程序 1:
int x = 80;
if (x >= 80)
{printf("Hello World! \n");
}
else if (x = 40)
{printf("Hello Bcdaren! \n");
}
else
{printf("GoodBye! \n");
}
Hello World!
程序 2:
int x =2 ,y = 3,z = 4;
int n;
if(x >= y)if(z == 4)n = x + y + z;
else
{n = x * y * z;
}
printf("%d \n",n);、
24
6.将 三目表达式转换成 if else 表达式。 (a > b)? (a > c ? a : c):(b > c ? b : c);
if(a>b)
{if(a>c)printf("%d",a);elseprintf("%d",c);
}
elseif(b>c)printf("%d",b);elseprintf("%d",c)
7.输入三角形的三条边长,求三角形的周长和面积,判断构成的三角形是何种三角形(正三角形,等腰三角形,直角三角形),若不能构成三角形,输出提示。
#include<stdio.h>int main()
{int a,b,c,l;scanf("%d%d%d",&a,&b,&c);if (a+b<c||a+c<b||b+c<a){printf("不能构成三角形");}else{ l = a + b + c;if(a==b&&a==c)printf("正三角形\n");else if(a==b||b==c||a==c)printf("等腰三角形\n");else if(a*a+b*b==c*c||a*a == b*b + c*c ||a*a + b*b == c*c)printf("直角三角形\n");elseprintf("普通三角形\n");printf("%d",l);}return 0;
}
(注: int x ; scanf("%d",&x); // 表示从键盘接受一个整数,存入变量 x 中)
switch语句
1.switch语句
switch(表达式x)
{case 常量N;//字符也可以,字符也是常量。会转换成ACSII码break;case 常量N;break;default;break;
}
说明:
<1> 表达式x必须是整数类型
<2> M K 必须是常量
switch语句的特点
- 见到break才结束,case1忘记写,则继续执行下面的操作,直到break才退出switch语句
- 没有匹配的表达式,会执行default分支,如果没有defaulit分支,则直接跳过switch语句,如果不需要default。
- default分支可以放在任何位置,不是必须放在最后
- 分支可以合并
#include <stdio.h>
int x = 0;
switch(x+1)
{case 1:printf("case1执行了");break;case 2:case 3:case 4:printf("error");break;//条件可以合并}
与if…else语句的区别
如果分支多,效率高//4
if…else语句适合判断区间,而switch不适合
练习
键盘输入 年 月 日,计算这一天是这一年的第几天
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|
30 | 28/29 | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 |
1 | -2 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 |
0 | 1 | -1 | 0 | 0 | 1 | 1 | 2 | 3 | 3 | 4 | 4 |
#include<stdio.h>
int main()
{int y,m,d;scanf("%d%d%d",&y,&m,&d);int today;today = (m-1)*30+d;switch(m){case 2:today+=1;break;case 3:today-=1;break;case 6:case 7:today+=1;break;case 8:today+=2;break;case 9:case 10:today+=3;break;case 11:case 12:today+=4;break; }if(y%4==0&&m>2){today += 1;}printf("今天是第%d天",today);return 0;
}
单步调试
一步一步执行调试
设置断点F9,取消断点F9
F5启动程序
shift+F5停止程序
F5单步走
while语句
1.while表达式
while(表达式){//代码;}
2.while语句举例
输出1000行“hello world”
#include<stdio.h>
int main()
{int i = 0;while(i<100){printf("hello world\n");i++;}return 0;
}
输出数组
#include <stdio.h>void main()
{int arr[] = {1,2,3,4,5,6,7,8,9,10};int nlength = sizeof(arr)/sizeof(int);int i = 0;while(i < nlength){printf("%d\n",arr[i]);i++;}
}
断点只能写在有语句的地方
为数组的成员赋值,值得电容为下标*2:arr[i] = i * 2;
#include<stdio.h>
void main()
{int arr[20] = {0};int nlength = sizeof(arr)/sizeof(int);int i = 0;while(i<nlength){arr[i] = i*2;i++;}i = 0;while(i < nlength){printf("%d\n",arr[i]);i++;}
}
打印一个数组成员的值(只打印值大于10的)
#include<stdio.h>
void main()
{int arr[20] = {0};int nlength = sizeof(arr)/sizeof(int);int i = 0;while(i<nlength){arr[i] = i*2;i++;}i = 0;while(i < nlength){if (arr[i]>10)printf("%d\n",arr[i]);i++;}
}
使用冒泡算法比较排列数组
int arr[] = [3,1,4,2,5,8,6];
int nlength = sizeof(arr)/sizeof(int);
int i = 0,k = 0;
int temp = 0;
while (k<(nlength-1))//控制循环次数
{while(i<(nlength-1))//元素比较,交换{if(arr[i]>arr[i+1]){temp = arr[i];arr[i] = arr[i+1];arr[i+1] = temp;}
}//代码要运行六次
使用continue打印数组偶数
#include<stdio.h>
void main()
{int arr[] = {21,34,53,54,65,76,34};int nlength = sizeof(arr)/sizeof(int);int i = 0;while(i< nlength){if (arr[i]%2!=0){i++;continue;}printf("%d\n",arr[i]);i++;}getchar();
}
练习
1.求 1 到 m 间所有奇数的和
#include<stdio.h>void main()
{int i = 1;int m;scanf("%d",&m);int sum = 0;while(i<=m){if (i%2 == 1)sum += i;i++;}printf("%d",sum);
}
2.求两个数的最大公约数和最小公倍数
3.从键盘循环接收字符串,并统计字母,空格,数字及其他字符的个数,回车结束
4.猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾就多吃了一个。第二天早上又将剩下的桃子吃了一半,还是不过瘾又多吃了一个。以后每天都吃前一天剩下的一半再加一个。到第 10 天刚好剩一个。问猴子第一天摘了多少个桃子?
5.打印 9*9 乘法表
#include<stdio.h>
int i,j;
void main()
{int i = 1;while(i<=9){int j = 1;while(j<=i){printf("%d*%d=%d ",i,j,i*j);j++;}i++;printf("\n");}getchar();
}
6.请用 while 循环打印如下图案
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
7.小芳的妈妈每天给她 2.5 元,她都会存起来,但是每当这一天是存钱的第 5 天时或者 5 的倍数的话,她都会花去 6 元钱。请问,经过多少天小芳才可以存到 100 元。
8.使用 while 循环,拼接两个字符串。
do…while语句
1.do…while语句
do
{}while(表达式x);
说明:
- 执行do{}里面的代码
- 判断表达式x是否为真,为真时继续
#include<stdio.h>
void main()
{int arr[] = {1,4,6,7,9,12,44,34};int nlength = sizeof(arr)/sizeof(int);int i = 0;do{if(arr[i] == 12){break;}printf("%d\n",arr[i]);//不成立也会成立}while(i < nlength);//1时不断执行
}
特点
至少会执行一次,所以,通常用来实现
做到…直到…为止
举例:
从键盘上输入字符,并显示,直到输入TAB为止
#include <stdio.h>
void main()
{char cInput;do{cInput = getchar();printf("%c\n",cInput);getchar();}while(cInput != '\t');
}
练习
1.求 1~100 之间数的每位数的乘积大于每位数的和的数
==2.==输入一批非 0 数,直到输入 0 时为止,计算其中奇数的平均值和偶数的乘积。
#include<stdio.h>
void main()
{int cInput;int a=0,b=1,i=1;do{scanf("%d",cInput);if (cInput%2 == 0)b = b*cInput;else{a+=cInput;i++;} }while(cInput = 0);int av = a/i;printf("%d %d\n",av,b);
}
3.计算 PI/4 = 1 - 1/3 + 1/5 - 1/7 +…,直到最后一项小于 10 负 6 次方。
4.编程将所有“水仙花数”打印出来,并打印其总个数。 “水仙花数”是一个 各个位立方之和等于该整数的三位数
5.验证“角谷猜想”, 判断给定的一个自然数,若为偶数除以 2,若为奇数则乘 3 加 1,得到一个新的自然数后按照上面的法则继续演算,一直到结果变为 1,并且将每一步的运算过程和得到的新的自然数显示出来。
6.百鸡问题:一只公鸡值 5 元,一只母鸡值 3 元,而 1 元可买 3 只小鸡。现有 100 元钱,想买 100 只鸡。问可买公鸡、母鸡、小鸡各几只?
7.编程实现:某人想将手中一张面值 100 元的人民币换成 5 元(可单换 20 张)、1 元(可单
换 100 张)和 0.5 元(可单换 200 张)面值的票子,但要求 100 元换以上的零钱共 100 张,
且要求每种不少于 1 张,共有多少种兑换方法。
8.韩信点兵:韩信才智过人,从不直接清点自己军队的人数,只要让士兵先后以三人一排、
五人一排、七人一排地变换队形,而他每次只掠一眼队伍的排尾就知道总人数了。输入 3
个非负整数 a,b,c,表示每种队形排尾的人数(a < 3,b < 5,c < 7),输出总人数的最小值
(或报告无解)。已知总人数不小于 10,不超过 100。
9.一辆卡车违反交通规则,撞人后逃逸。现场有三位目击证人,但都没有记住车号,只记下
车号的一些特征。甲说:牌照的前两位数字是相同的。乙说:牌照的后两位数字是相同的,
但是和前两位不同。丙说;四位的车号刚好是一个整数的平方(四位车牌号>999)。请用以上
线索求出车号。
\10. 有一对兔子,从出生后的第三个月起每个月都生一对兔子。小兔子长到三个月以后每个
月都生一对兔子。小兔子长到第三个月以后每个月又生一对兔子。假设所有的兔子都不死,
问 30 个月内每个月的兔子总数是多少。
11.如果整数 A 的全部因子(包括 1,不包括 A 本身)之和等于 B,且整数 B 的全部因子(包
括 1,不包括 B 本身)之和等于 A。则将 A 和 B 称为亲密数。求 3000 以内的全部亲密数。
for语句
#include<stdio.h>
void main()
{int arr[] = {1,3,6,8,9,1,2,31}
}
函数
函数
1.什么是函数
函数就是一系列指令的集合,可以完成某一些特定的功能
2.函数定义的格式
返回类型 函数名(参数列表){函数体;
}
说明:
- 函数名:字母,数字和下划线的组合
- 参数列表::可以没有,可以有多个,中间用“,”隔开:int x,int y。
- 返回值类型:函数结果的类型,可以没有void。
- 函数体:也可以是函数的具体实现
3.有参数有返回值的函数
编写一个函数,能够对任意两个整数实现加法操作,并且返回结果
#include <stdio.h>int Plus(int x,int y)//占位符,int是返回类型,形式参数
{int z = x + y;return z;
}
避免编写相同的代码
练习
1.编写一个函数,求两个数的最大公约数并返回。
2.编写一个函数,求一个 int 类型数组所有成员的平均值,并输出数组中最接近平均值的成
员。
3.实现一个函数判断 year 是不是润年,是返回 1,不是返回 0。
4.实现一个函数,判断参数是不是素数,是返回 1,不是返回 0。
5.编写一个函数,可以将字符串 2 合并到字符串 1 中。
6.编写一个函数,打印 x*x 乘法表 x 为参数。
7.编写一个函数, int fun(int a,int b, int c);如果三个数相等返回 1,其中两个数相等返回 0,其他情况返回-1
8.编写一个函数,输出 x 以内所有的素数,x 为参数
9.一函数,输入一行字符,将此字符串中最长的单词输出,单词间以空格分隔。
10.定义一个函数,使给定的二维数组(3×3)转置,即行列转换,并输出转换前和转换后的数据。
函数的灵活使用
1.函数的嵌套调用
函数声明有返回类型,必须使return进行返回
#include <stdio.h>
int Plus(int x, int y)
{int r = x + y;return r;
}int Plus2(int a,int b,int c)
{int r = Plus(a,b);int m = Plus(r,c);return m;
}//函数嵌套太多不好int main(int int)
2.函数可以作为表达式来使用
输出某一个数组的素数
#include <stdio.h>
//判断某个数是否为素数,是1不是0
int IsPrime(int n)
{int r = 1;for(int i = 2; i<n; i++){if (n%i == 0){r=0;break;}return r;}
}
int main()
{int arr[] = {3,6,7,9,10,11,12};int nlength = sizeof(arr)/sizeof(int);for(int i=0; i<n; i++){if(IsPrime(arr[i]))//将函数直接作为表达式来使用{printf("%d \n",arr[i]);}}return 0;
}
3.for循环的理解
#include<stdio.h>void Fu1()
{printf("Fu1.....");
}
void u2()
{printf("Fu2.....");
}
int Fu3()
{printf("Fu3.....");return 1;
}
void Fu4()
{printf("Fu4.....");
}int main()
{for(Fu1;Fu2:Fu3){Fu4;}return 0;
}
函数有返回值,就是一个值
4.函数结束的标识
一个函数只能执行一次return
return 可以写多个,但只能执行一次
建议大家定义一个变量r
定义返回结果
然后最后return r
函数的参数传递
1.有参函数的调用
int Plus(int x, int y)//形式参数,占位符
{return x+y;
}int r = Plus(1,2)//实参
2.值传递
#include <stdio.h>
void Fun(int x)
{x = x+1;
}int main()
{int a = 10;Fun(a);//只能传递值printf("%d \n",a);return 0;
}
3.将数组作为参数传递
#include <stdio.h>
void Fun(int arr[])
{arr[0]=100;arr[1]=200;
}int main()
{int arr[] = {1,2,3,4,5,6,7,8,9,10};int nlength = sizeof(arr)/sizeof(int);for(int i = 0;i<nlength;i++){printf("%d ",arr[i]);}printf("\n-----------------------\n");Fun(arr);for(int j=0;j<nlength;j++){printf("%d ", arr[j]);}return 0;
}
数组作为参数传值的时候,是把当前数组的地址,是通过地址进行传递
int类型作为参数传递的时候传递的是值
变量的作用范围
#include <stdio.h>
int x = 100;//全局变量
void Fn1()
{int y = 200;
}
void Fn2()
{}
int main()
{}
全局变量与局部变量
总结
函数的递归调用
1.函数自己调用自己
#include<stdio.h>void Fn()
{printf("执行了\n");Fn();
}int main
代码 | 内存 | |
---|---|---|
栈 | 函数运行时所使用的内存称为栈 | |
当程序用完之后依然没有使用栈内存,会报错 | 函数执行完会释放内存 |
什么是栈溢出
2.递归的经典应用
1.求n的阶乘
#include <stdio.h>
int Fn(int n)
{if(n==1||n==2)return n;return n*Fn(n-1);}
int main()
{int r = Fn(4);
}
2.斐波那栔数列:0,1,1,2,3,5,8,13…
求给定的x给y的值(y = Fn(x))
#include<stdio.h>
int Fn(int n)
{if(n == 0)return 0;if(n < 2)return 1;return Fn(n-1)+Fn(n-2);
}
int main()
{int r = Fn(4);printf("%d",r);
}
总结
尽量不要使用,递归非常浪费内存
结构体
结构体的使用
1.引出问题
当你需要一个容器能够存储1个字节,怎么做?//char
当你需要一个容器能够存储4个字节,你会怎么做?//int arr[10]
数组解决不了 成员之间类型不一样的问题
游戏角色
生命 | 魔法 | 技能 | 经验 | 血量 | 等级 | 移动速度 |
---|---|---|---|---|---|---|
int | int | int | int | int | int | float |
2.结构体类型的定义
#include <stdio.h>
//先定义类型 == int/float/double
struct stPoint//看成声明一种类型
{int x;int y;
};//此时不占用内存空间
//定义类型的变量
struct stPoint point;
int main()
{stPoint point = {0};//初始化
}
struct 类型名
{//可以定义多种类型int a;int b;float c;
};
结构体在定义时要字节对齐
比如都是char,会自动扩充至int
3.结构体赋值
//单独赋值
int main()
{stStudent studen = {0};//单独赋值student.stucode = 101;student.stuAge = 18;student.stuSex = 'M';strcpy(student.stuName,"编程达人")
}
4.如何读写变量中的值
int main()
{stStudent studen = {0};//单独赋值student.stucode = 101;student.stuAge = 18;student.stuSex = 'M';strcpy(student.stuName,"编程达人");int x = student.stucode;printf("%s \n",student.stuName);strcpy(buffer,student.stuName);
}
结构体的大小未必是整体大小
练习
1.为什么要定义结构体类型?
当数组内的类型不一样时,定义结构体类型
2.结构体类型可以在函数里定义吗?
可以,但是要赋值,否则会出现乱码
3.代码这么写,有错误么
struct Person
{char name[] ="itcast";int age=20;
};
有错误
strcpy(Person.name,"itcast")
4.申请几个结构体变量,分别用视频中的方法对它赋值。
#include <stdio.h>
#include <windows.h>
struct Books
{int type;char name[20];char author[5];int Book_ID;
};int main()
{struct Books Book = {2,"typora","tom",123123};printf("%s ",Book.author);strcpy(Book.author,"tony");printf("%s ",Book.author);return 0;
}
5.定义结构体Student,包含成员姓名,年龄,身高,嵌套包含结构体Score,。定义结构体Score,包含成员 数学,语文,英语,三科成绩。申请结构体Student变量,对其成员赋值后打印输出至控制台。
#include <stdio.h>
#include <windows.h>struct Scores//声明类型
{int Math;int Chinese;int English;
};struct Students
{char Name[10];int Age;float Height;struct Scores score;
};int main()
{struct Students student = {"Tom",14,176,0};printf("%s\n",student.Name);printf("%d\n",student.score.Math);printf("%d\n",student.score.English);student.score.Math = 67;student.score.Chinese = 78;student.score.English = 87;strcpy(student.Name,"Tony");printf("%d\n",student.score.Math);printf("%d\n",student.score.English);printf("%s\n",student.Name);return 0;
}
6.定义一个结构体表示点的 x,y 坐标,依次读入三个正整形坐标值,输出三个点构成的三角形面积
用到头文件#include<math.h>用到开方函数 sqrt().
7.在全局定义的结构体和在局部定义的结构体有什么区别?
<1>编写一函数,计算两个日期之间的时间差,并将其值返回。
日期以年、月、日表示。“时间差”以天数表示。注意考虑日期之间的闰年。
函数的输入参数为日期 1 和日期 2,函数的返回值为时间差,单位为天数。
<2>编写一程序,在主函数中输入两个日期,调用上述函数计算两个日期之间的时间差,并将结果输出。
结构体的其他特征
1.结构体参数传递
#include <stdio.h>
{int x;int y;
};
void MyPrint(stPoint point)//结构体也可以变量,你可以用其他任何地方当返回值
{printf("%d %d \n",point.x,point.y)
}
结构体参数为int/char/float/double等基本类型时,传递的是值,是在复制内容
参数为数组类型时,传递的是地址
2.结构体赋值
允许p=p2,结构类型相同
stPoint p = {0,0,0},p1 = {1,2,3},p2 = {3,3,3};
p1 = p2;//赋值
3.不推荐的写法
- 匿名结构体
- 直接定义变量
结构体数组
#include <stdio.h>//定义结构体类型
struct stStudent
{int Code;int level;
};int main()
{stStudent student[10]={{101,"zhang san"},{102,"li si"},{103,"wang wu"}};//如何定义一个结构体类型的数组//调用int x = student[1].Code;printf("%s \n",student[1].Name);//改student[2].Code = 100;strcpy(student[1].code,"sda");return 0;
}
练习
精简学生信息管理系统。
<1>定义结构体包含如下信息:学生姓名,性别,语文数学英语成绩。
<2>设某班有20个学生,请实现以下功能:
1.可以录入学生信息。
2.可以删除学生信息。
3.可以查找学生信息。
#include <stdio.h>struct students
{char Name[10];char gender;int math;int chinese;int english;
};
struct students student[20];
int main()
{for(int i=0;i<20;i++){strcpy(student[i].Name,"张三");student[i].gender = 1;student[i].math = 87;student[i].english = 87;student[i].chinese = 97;}
}
指针类型
指针类型
1.定义带*的类型的变量
char x; | char* x; |
---|---|
short y; | short* y; |
int z; | int* z; |
float f; | float* f; |
double d; | double* d; |
student st; | student* st; |
总结:
1.带有*变量类型的标准写法:变量类型 * 变量名
2.任何类型都可以带 * 加上以后就是新的类型,统称为“指针类型”
3.*可以是任意多
赋值
#include <stdio.h>
struct Point
{int x;int y;
};int main()
{char* x;int* y;Point* point;x = (char*)1;//y = (char*)2;//指针类型的赋值point = (Point*)0;printf(sizeof());
}
指针的本质是类型
指针本质类型的4个字节
指针类型的运算
++
–
运算幅度是类型砍掉一个类型之后的类型宽度
总结:
1.不带 * 类型的变量,++ 或者 – 都是加 1或者减1
2.带类型的变量,++或者–新增(减少)的数量是去掉一个后变量的宽度
指针类型的变量宽度永远是4字节
还可以跟整数做运算
指针类型的使用
任何一个变量都加 * 变为新的类型
指针类型
内存4GB | |
---|---|
BYTE | 0 |
内容-12345 | 1(当前内存的编号,代号不需要存储) |
2 | |
… | |
0xFFFFFFFF |
1.取地址符&
#inlcude <stdio.h>
struct Point
{int x;int y;
}int main()
{char a = 9;//&a char*short b = 1;//&b short*int c = 2;//&c int8Point p = {3,3};//&d point*char* pa = (char*)0x12FF7c;char x = *pa;//指针变量*pa = 8;printf("%d \n",x);pa->x = 4;pa->y = 5;printf9("%d %d \n", pa->x,pa->y);return 0;
}
指针: 间接引用运算符 *
nurse = 22;
ptr = &nurse;
val = *ptr;
变量也有两个属性:地址和值。地址就是变量在计算机内部的名称
许多程序中,地址都归计算机管,对程序员隐藏。然而在C中,可以通过&运算符访问地址,通过*运算符获得地址上的值。
简而言之,普通变量把值作为基本量,把地址作为通过&运算符获得的派生量,而指针变量把地址作为基本量,把值作为通过*运算符获得的派生量。
const
有时需要把数组设置为只读,这样程序只能从数组中检索值。不能把新值写入数组,要创建只读数组,应该用const声明数组
动态申请内存
1.引出问题
如果我在程序编译的时候,我并不知道存多少
2.内存管理
代码区
全局变量区
常量区
栈(参数局部变量)
堆
#include<stdio.h>
#include <windows.h>struct Student
{int x;int y;
}
void main()
{//intint* p = (int*)malloc{100*sizeof(int)};//(int*)强制类型转换char* p = (char*)malloc{200*sizeof(char)};//申请结构体Student* p = (Student*)malloc(100*sizeof(Student));free(p);//释放掉内存
}
文件类型
堆内存 | 有人帮你记录 |
---|---|
1-5int | Begin-Bigin+5 |
2-8int | Begin-Bigin+8 |
3-9int | Begin-Begin+9 |
会出现碎片
导致出现一个空白的内存
整个堆空间有一部分用了,有一部分没用,整个内存没有连续,当你申请一个较大内存的时候
注意事项
- 如果申请成功,则会返回地址,返回成功才能使用
- malloc申请的内存,必须使用free释放掉
- free之后,将指针置空,避免出现野指针…
文件
1.什么是文件?为什么要使用文件?
用于永久存储数据
2.文件的特点
1.文件名
2.文件路径
3.文件大小
4.文件属性:只读、可读可写,隐藏
文件类型
文本文件
二进制文件
文件读写
1.C语言中由于操作文件的相关函数
头文件
#include <stdio.h>
相关函数
fopen、fclose、fread、fwrite、fseek等
文件操作流程
第一步:打开文件
第二步:处理文件
第三步:关闭文件
#include <stdio.h>
#include <windows.h>void TestWriterfile()
{//1.打开文件,2.向文件中写数据,3.关闭文件char szPath[] = "C:\\Test.txt";FILE* pFile = NULL;char szBuffer[0x10];//创建缓冲区pFile = fopen(szPath,"wb");//wb,如果文件不存在,创建一个新的文件,如果文件存在则清零if(pFile == NULL){printf("文件打开失败 \n");return;}//从文件中写数据memset(szBuffer,0,sizeof(szBuffer));strcpy(szBuffer,"China");nWrite = fwrite(szBuffer,1,strlen(szBuffer),pFile);//一次多少,写多少个,写入文件if(nWrite == 0){printf("文件写入失败");return;}//关闭文件fclose(pFile);
}void main()
{TestWritefile()
}
预处理之宏定义
什么是预处理
预处理一般是指在程序源代码被转换为二进制代码之前,由预处理器对程序源代码文本进行处理,处理后的结果再由编译器进一步编译。
预处理功能主要包括宏定义,文件包含,条件编译三部分
C语言基础语法(2遍)相关推荐
- Go语言基础语法--注释、基础结构2
章节 GO语言基础语法--注释.基础结构(重要) 1.GO语言基础语法---注释.基础结构 //程序所属的包,且必须在源文件代码第一行 package mainimport "fmt&quo ...
- 一篇文章带你玩转C语言基础语法5:条件判断 if else 语句与分支 。(千字总结)
我的个人主页:☆光之梦☆的博客_CSDN博客-C语言基础语法(超详细)领域博主 欢迎各位
- Go语言 基础语法学习 (未完待更......
文章目录 一 Go语言结构 1 Go Hello world实例 2 执行Go程序 二 Go语言基础语法 1 Go标记 2 行分隔符 3 注释 4 标识符 5 一些关键字 6 Go语言的空格 7 格式 ...
- C语言基础语法【1】
目录 1.在linux系统编写C语言,基本命令:变量.常量.标识符 2.数据类型.取值范围.字符串 3.短路原则.类型转换 4.switch语句.for.while循环.死循环 1.在linux系统编 ...
- 一篇文章带你玩转C语言基础语法。2:数据类型。千字总结
我的个人主页:☆光之梦☆的博客_CSDN博客-C语言基础语法(超详细)领域博主 欢迎各位
- GO 语言基础语法一 (快速入门 Go 语言)
Go语言基础语法 一. golang 标识符,关键字,命名规则 二. golang 变量 三. golang 常量 四. golang 数据类型 五. golang 布尔类型 六. golang 数字 ...
- 【Go编程语言】 Go语言基础语法
Go语言基础语法 文章目录 Go语言基础语法 一.注释 1.单行注释 2.多行注释 二.变量 1.变量的定义 2.变量的初始化 3.理解变量(内存地址) 4.变量交换 5.匿名变量 6.变量的作用域 ...
- 【Day4 C语言基础语法学习-3】
Day4 C语言基础语法学习-3 一 数组 1.1 数组的概念 1.2 一维数组 1.2.1 一维数组的定义 1.2.2 一维数组的性质 1.3 一维数组的初始化和遍历 1.4 冒泡排序法 二.二维数 ...
- 【Day3 C语言基础语法学习-2】
Day3 C语言基础语法学习-2 一.输入输出函数 1.1 getchar()/putcgar() 1.1.1getchar() 1.1.2 putchar 1.2 gets()/puts() 1.2 ...
最新文章
- 【安全加密技术】 对称加密
- SpringBatch学习一个Demo项目
- Nginx重定向到子目录问题
- 性能服务器解读,【MySQL数据库】第三章解读:服务器性能剖析(上)
- python画图fig.show()一闪而过的解决方法
- 汇编写java模块_java – maven汇编插件moduleset源指令不包括任何文件,不符合附带的模块...
- std::map的insert和下标[]访问
- LeetCode 962. 最大宽度坡(单调栈)
- 300php是多少人民币,GV300S登陆欧洲市场 售价约为3.82万人民币
- 走进WPF之开发类似Visio软件
- 墨卡托投影和高斯-克吕格 (Gauss-Krüger) 投影
- ECharts(官网:http://echarts.baidu.com)
- 有了PDA手持终端,仓库再也不愁盘点了
- 几款优秀的文档管理系统
- 微信页面隐藏分享按钮
- postman-批量导入数据
- 如何实现微信内域名防封,微信域名防封跳转
- 立象(ARGOX) 条码标签打印机通用库 PLLB(BWIN-SCAPI)
- ui动画_ui后效动画指南
- 安卓小项目之EveryDay(6)----使用第三方平台获取短信验证码