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 
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
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
//变量类型 变量名字 值
int main()
{
    char x = 10;//可以放进程序里面可以放到程序外面,但是如果放进程序里面,仅仅是当前程序使用,其他程序无法使用
    printf("%d",x);
    getchar();
    return 0;
}

放到函数里面必须有一个明确的初始值

放到函数外面称为全局变量

为什么要使用变量

变量本身是一个内存

变量的本质是容器,里面可以存储任意类型的数据

实例

可以根据用户输入圆的半径,计算出圆的面积。

#include 
#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 

char a = 0x12;//一个字节
short b = 0x1234;.//两个字节
int c = 0x12345678;//四个字节
printf("%p,%p,%p \n",&x,&y,&z)

大端小端针对的是数据超过1个字节的存储

小端模式:数据低位在内存地址编号低位,数据高位在高位

大端模式:数据高位在内存地址编号低位,数据高位在低位

程序在断点才可以看memory

float使用二进制规范存储,将小数点变为二进制IEEE规则

#include 

int main()
{
    char x = 0x12;
    short y = 0x1234;
    int z = 0x12345678;//12 34 56 78
                      //0019FF28-0019FF24
                      //78 56 34 12
    printf("%p,%p,%p\n,"&x,&y,&z);
    getchar();//断点在getchar不能看memory
    return 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 

int main()
{
    int x = 0xFFFFFFFF;
    prinf("%u,%d\n",x,x);
    return 0;
}

%u:无符号数的输出标记

%d:有符号数的输出标记

有符号数与无符号数在存入内存的时候是相同的,比如

int a = -1;
unsigned a = -1;
//此两者在存储时是相同的,存入内存的数值都是
//FFFF FFFF
#include 

int main()
{
    unsigned char x = 0xFF;//1111 1111
    unsigned int y = x;//0000 0000 1111 1111
    int y = x;//1111 1111 1111 1111
    printf("%p,%p\n",x,y);
    return 0;
}

%x:十六进制输出标记

%p:类似于地址,全部位输出标记

有符号数与无符号数区别

  • 拓展的时候有差异
#include 

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 

int main()
{
    unsigned int a = -1;
    if (a>1)
    {
        printf("%p",a);
    }
    return 0;
}

总结

  1. 无论有符号数与无符号数,内存存储的方式是一样的,补码
  2. 有符号数与无符号数在使用的时候,主要的区别是:

<1>拓展的时候

<2>运算的时候

只有整数才有有符号与无符号之分

浮点数另算

字符与字符串

单引号==’ '==只是单个字符

ACSII表

A-65

a-97

putchar()只能打印一个字符,给他任何数字都会进行查表,然后输出表的对应值

转义字符 \a = 7, \n = 10

#include 

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-右边输入名称

训练

  1. 创建一个长度为10的整型数组,并为这个数组赋值(值是下标的2倍);
  2. 将上题中数组的第一个元素与最后一个元素的值交换。
#include 
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++)//先参与运算,再自加

运算符优先级别==()==

()具有最高优先级

算术表达式的结果类型

short
int
char
unsigned
double
float
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. 程序中所有数在计算机内存中都是二进制的形式存储的
  2. 位运算就是直接对整数在内存中的二进制位进行操作

位运算能做什么

计算机底层相关领域:

加密解密 安全 反病毒 反外挂

位运算能够精确的对某一个位进行操作

位运算有哪些

计算方式 计算过程
按位与 & 全部是1取1
按位或 | 有1取1
按位异或 ^ 不同为1,相同为0
按位取反 ~ 取反
左移 移位运算 <<
右移 移位运算 >> 无符号数补0,有符号数补符号位

位运算举例

如何将二进制数中的某一个位置修改为1? //3位

x|4//修改某一个位,通过与运算
    1010 1010
    0000 0100
    ---------
    1010 1110

如何将二进制数中的某一位置修改为0; //3位

x&FB
    1010 1110
    1111 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< 0001 0000
修改第n位的值为0 0001 0000
按位与 &((2字节长度-1)-2n-1) 1110 1111
0000 0000

设置相反x^(1<

5. 设 int a = 2; int b = 5; 使用位运算,交换两个变量的值,并打印。

2 0000 0010
5 0000 0101

自己的见解

#include
int a = 2;
int b = 5;
void main()
{
    a=(a << 1)|1;
    b=b >> 1;
    printf("%d %d",a,b);
}							

王者见解

#include
int a = 2, b= 5;
void main()
{
    a = a^b;
    b = b^a;
    a = a^b;
    printf("%d%d",a,b);
}

6.使用位运算 获取 int 类型的最大值和最小值,并打印

#include
void main()
{
    int a;
    a=0;
    printf("%x",~i);
}

运算符种类

赋值运算符

赋值是一个动作,表达式是一个数

x = x + 8;
x += 8

标准运算

拓展赋值

关系运算符

  1. 什么是真(非0),假为0
  2. 关系运算符返回结果为真假

关系运算符用于比较两者的关系

关系运算符也是双目运算符

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. 当表达式1为真时,并且表达式2为真时,整个表达式的结果为真,否则为假
  2. 短路特征,当表达式1为假时时候,后面的表达式将不再执行
逻辑或||,可以理解成“或者”
  1. 当表达式1为真或者表达式2为真时,整个表达式的结果为真,否则为假
  2. 短路特征,当表达式1为真的时候,后面的表达式将不再执行

非!

加在任何表达式的前面,改变表达式的值

练习

int x =4; int y = 7; int z = 3;用三目表达式求出三个变量中的最大值

自己迂腐之见

#include
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);
    else
        printf("最大值为z:%d",z);
	getchar();
	getchar();
}

王者级别

#include
int x=3,y=4,z=7;
void main()
{
    printf("%d",x>y?(x>z?x:z):(y>z?y:z));
}

不运行程序,说出打印结果,为什么?

#include
void main()
{
    int x;
    printf("%d\n",x = 60);
    printf("%d\n",x ==60);
}

60//表达式为值

1//有数为真为1

不运行程序,说出结果,并解释.

#include
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
//核心就是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
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();
    else
        printf();
}

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
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 

int x;
void main()
{
    scanf("%d",&x);
    if(x%4==0)
        printf("%d年是闰年",x);
    else
        printf("%d年不是闰年",x);
}

3.一个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同。(精)

#include
int a;
void main()
{
    scanf("%d",&a);
    if((a/10000)%10==(a%10)&&(a/10)%10==(a/1000)%10)
        printf("是回文数\n");
    else
        printf("不是回文数\n")
}

4.从键盘接收一个字符,如果是小写字母,就输出对应的大写字母。如果是大写字母,输出对应的小写字母。

#include
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);
    else
        printf("请重新输入");
	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);
    else
        printf("%d",c);
}
else
    if(b>c)
        printf("%d",b);
    else
        printf("%d",c)

7.输入三角形的三条边长,求三角形的周长和面积,判断构成的三角形是何种三角形(正三角形,等腰三角形,直角三角形),若不能构成三角形,输出提示。

#include

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");
        else
            printf("普通三角形\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语句的特点

  1. 见到break才结束,case1忘记写,则继续执行下面的操作,直到break才退出switch语句
  2. 没有匹配的表达式,会执行default分支,如果没有defaulit分支,则直接跳过switch语句,如果不需要default。
  3. default分支可以放在任何位置,不是必须放在最后
  4. 分支可以合并
#include 
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
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
int main()
{
    int i = 0;
    while(i<100)
    {
        printf("hello world\n");
        i++;
    }
    return 0;
}

输出数组

#include 

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
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
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
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

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
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)

说明:

  1. 执行do{}里面的代码
  2. 判断表达式x是否为真,为真时继续
#include
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 
void main()
{
    char cInput;
    do
    {
        cInput = getchar();
        printf("%c\n",cInput);
        getchar();
    }while(cInput != '\t');
}

练习

1.求 1~100 之间数的每位数的乘积大于每位数的和的数

==2.==输入一批非 0 数,直到输入 0 时为止,计算其中奇数的平均值和偶数的乘积。

#include
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
void main()
{
    int arr[] = {1,3,6,8,9,1,2,31}
}

函数

函数

1.什么是函数

函数就是一系列指令的集合,可以完成某一些特定的功能

2.函数定义的格式

返回类型 函数名(参数列表)

{
    函数体;
}

说明:

  1. 函数名:字母,数字和下划线的组合
  2. 参数列表::可以没有,可以有多个,中间用“,”隔开:int x,int y。
  3. 返回值类型:函数结果的类型,可以没有void。
  4. 函数体:也可以是函数的具体实现

3.有参数有返回值的函数

编写一个函数,能够对任意两个整数实现加法操作,并且返回结果

#include 

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 
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 
//判断某个数是否为素数,是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

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 
void Fun(int x)
{
    x = x+1;
}

int main()
{
    int a = 10;
    Fun(a);//只能传递值
    printf("%d \n",a);
    return 0;
}

3.将数组作为参数传递

#include 
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 
int x = 100;//全局变量
void Fn1()
{
    int y = 200;
}
void Fn2()
{
    
}
int main()
{
    
}

全局变量与局部变量

总结

函数的递归调用

1.函数自己调用自己

#include

void Fn()
{
    printf("执行了\n");
    Fn();
}

int main

代码 内存
函数运行时所使用的内存称为栈
当程序用完之后依然没有使用栈内存,会报错 函数执行完会释放内存

什么是栈溢出

2.递归的经典应用

1.求n的阶乘

#include 
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
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 
//先定义类型 == 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 
#include 
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 
#include 

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用到开方函数 sqrt().

7.在全局定义的结构体和在局部定义的结构体有什么区别?

<1>编写一函数,计算两个日期之间的时间差,并将其值返回。

日期以年、月、日表示。“时间差”以天数表示。注意考虑日期之间的闰年。

函数的输入参数为日期 1 和日期 2,函数的返回值为时间差,单位为天数。

<2>编写一程序,在主函数中输入两个日期,调用上述函数计算两个日期之间的时间差,并将结果输出。

结构体的其他特征

1.结构体参数传递

#include 
{
    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.不推荐的写法

  1. 匿名结构体
  2. 直接定义变量

结构体数组

#include 

//定义结构体类型
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 

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 
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 
struct Point
{
    int x;
    int y;
}

int main()
{
    char a = 9;//&a char*
    short b = 1;//&b short*
    int c = 2;//&c int8
    Point 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
#include 

struct Student
{
    int x;
    int y;
}
void main()
{
    //int
    int* 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

会出现碎片

导致出现一个空白的内存

整个堆空间有一部分用了,有一部分没用,整个内存没有连续,当你申请一个较大内存的时候

注意事项

  1. 如果申请成功,则会返回地址,返回成功才能使用
  2. malloc申请的内存,必须使用free释放掉
  3. free之后,将指针置空,避免出现野指针…

文件

1.什么是文件?为什么要使用文件?

用于永久存储数据

2.文件的特点

1.文件名

2.文件路径

3.文件大小

4.文件属性:只读、可读可写,隐藏

文件类型

文本文件

二进制文件

文件读写

1.C语言中由于操作文件的相关函数

头文件

#include

相关函数

fopen、fclose、fread、fwrite、fseek等

文件操作流程

第一步:打开文件

第二步:处理文件

第三步:关闭文件

#include 
#include 

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语言,c语言,编程语言)