c语言学习笔记

1.基本语法的含义

#include<stdio.h>
//stdio拆分来就是 standard 标准input输入out输出  h指head 头文件 stdio.h。include是预命令。
//这个文件可能会包含一个标准输入输出的头文件
int main(void)
{
	/* 我的第一个C程序 */
	printf("Hello,World!\n");
	//print 打印 f format 格式化
	//printf 格式化输出
	return 0;
}

2.char ch的作用

#include<stdio.h>
int main(void)
{
	char ch = 'a';//存储a
	//char-字符类型 像abc。。。 //ch是 向内存申请空间的变量【可以理解为指令】

return 0;

}

3.%c与\n的含义

#include<stdio.h>
int main(void)
{
	printf("%c\n,ch");  //%c--打印字符格式的数据【指令】\n表示换行  整个意思是 我以字符的形式来打印ch
	return 0;
}

4.打印 printf 格式化输出

#include<stdio.h>
int main(void)
{
	int age = 20;//age是年龄 在这一行年龄已被注释为20
	printf("%d\n", age);//%d--打印整型十进制数据,将age以整型十进制的形式打印出来 而上一行age已被定义为20 所以会打印出20

	return 0;

}

5.理解变量

#include<stdio.h>
int main(void)
{
	float a = 2.0;//像float int 等等后面是变量 不仅是a 等等
	printf("%f\n", a);
	return 0;
}

6.全局变量与局部变量

int num1 = 20;//全局变量,定义在代码块{}外的变量
#include<stdio.h>
int main(void)
{
	int num2 = 10;//局部变量,定义在代码块{}内的变量  
	return 0;
}

7.计算两个数的和

#include<stdio.h>
int main(void)
{
	int num1 = 10;
	int num2 = 20;
	int sum = 0;//c语言语法规定,变量要定义在当前代码块的最前面 不然会报错
	scanf("%d%d", &num1, &num2);//scanf是输入函数,输入数据时使用.scanf是C语言标准。但新版vs要用scanf_s
	sum = num1 + num2;
	printf("sum = %d\n", sum);
	return 0;
}

8.变量的作用域与生命周期

#include<stdio.h>
int main(void)
{
	{
		int num = 10;
	}//这里面的括号才是num的作用域
	printf("%d\n", num);//这里会出现报错是因为printf所在位置不是num的作用域【就是可以发挥作用的区域】
	return 0;
}//生命周期 局部变量 进入作用域 开始 出作用域结束 
 //全局变量 整个程序的生命周期

9.声明符号 extern

#include<stdio.h>
int main(void)
{
	extern int wwf;//声明符号。若我创建了另一个c文件 在其中定义  例  int wwf = 10
	//那么在此文件中我需要输入 extern int wwf;来声明 int wwf这个外部符号【即不在本c文件内的符号】
	printf("%d\n", wwf);
    //只有这样才能打印出wwf = 10
	return 0;

}

10. 宏定义

#define _CRT_SECURE_NO_WARNINGS 1//像scanf等c语言传统函数是不安全的,一些编译器会报错并且给出安全的版本。但也可以像前面一样宏定义来让他不警告。

int main(void)
{
	int num1 = 0;
	int num2 = 0;
	int sum = 0;
	scanf("%d%d", &num1, &num2);
	sum = num1 + num2;
	printf("sum =%d", sum);
		return 0;
}

11.scanf与scanf_s的认知

​ scanf()在读取数据时不检查边界,所以可能会造成内存访问越界:

1 //例如:分配了5字节的空间但是用户输入了10字节,就会导致scanf()读到10个字节

2 char buf[5]={‘\0’};

3 scanf(“%s”, buf);

4 //如果输入1234567890,则5以后的部分会被写到别的变量所在的空间上去,从而可能会导致程序运行异常。


​ 以上代码如果用scanf_s()则可避免此问题:

1 char buf[5]={‘\0’};

2 scanf_s(“%s”,buf,5); //最多读取4个字符,因为buf[4]要放’\0’

3 //如果输入1234567890,则buf只会接受前4个字符

12.const的含义与用法

#include <stdio.h>
int main(void)
{
	int num = 4;
	printf("%d\n", num);
	num = 8;
	printf("%d\n", num);
	return 0;
}
//打印出来后有4和8

#include <stdio.h>
int main(void)
{  //num是一个变量,但在前面加上const后就拥有了常属性,所以const num中的num是常变量-num是变量,但拥有常属性。
   //但是在需要用到常量表达式(包含常量,例一个数字9)时,不能用常变量。
   // int arr[10]      创建数组,[]中只能输入常量表达式,不能const int num = 10,再int arr[num]这是错误的。
   //const-const是一个C语言(ANSI C)的关键字,具有着举足轻重的地位。它限定一个变量不允许被改变,产生静态作用。
	const int num = 4;//但如果我们在int num前加上const,那么这个代码就跑不起来了,因为const修饰常变量,num用const修饰以后就不能变了printf("%d\n", num);
​	num = 8;//而我们又在这里定义为8,所以发生错误printf("%d\n", num);return 0;

}

13.define 定义标识符常量

#include<stdio.h>
int main(void)
#define max 10
{
	int arr[max] = { 0 };//不像12中用int定义的一样,用define定义一个常量 define max 10 ----定义max为常量10,此时int arr []中可以写入max
	printf("%d\n", max);//此时max也是可以打印的 打印出为10.而且max不在代码块里面,所以他是一个全局常量【应该可以这样理解】
	return 0;
}

14.枚举常量,enum-枚举名

为什么要用枚举?
#define MON 1
#define TUE 2
#define WED 3
#define THU 4
#define FRI 5
#define SAT 6
#define SUN 7
用枚举后
enum DAY{MON=1,TUE,WED, THU, FRI, SAT, SUN};
枚举后默认的第一个元素的整型为0 往后以此类推加一加一

15.常量总结

一.字面常量

二.const定义的常变量

三.define定义的常量

四.枚举常量

16.枚举

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
enum color
{
	red,
	yellow = 10
};

int main(void)
{
	printf("%d\n", yellow);
	return 0;
}
//打印出是10  red默认为0 yellow默认为1 但在enum的代码块中我将他 = 10
//但如果我是在int main的代码块中将yellow = 10 写入 那么会产生错误

17.字符串以及其结束标志\0

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{   //字符串---由双引号引起来的一串字符称为字符串字面值,或者简称字符串.
	char arr1[] = "abc";//数组
	char arr2[] = { 'a','b','c'};
	printf("%s\n", arr1);//打印出来是 abc
	printf("%s\n", arr2);//打印出来是abc烫烫烫烫
    //用调试中的监控来监控"abc"和{'a','b','c'}我们可以发现 前者除了abc外还有个\0 而后者没有.
    //但如果我们把arr2改成{'a','b','c',\0},  (\0也可改为0)因为\0也表示0再来打印就是只打印abc了。\0是一个转义字符,计算字符串长度时是结束标志,不算作字符内容。
    // \0是字符串结束的标志,printf中检测到\0就会停止打印了。而出现烫烫烫烫是因为打印完abc后没有结束标志 继续随机生成的。
	return 0;
}

18.ASCII表

​ //数据在计算机上存储的时候,是以二进制来存储的。那么像一些特殊字符 %¥a等等,就用数字来指代他们。而为此制定了一个ASCII表
​ //例如a-97 A-65 字符所对的值叫做 ASCII码值
ASCII表

19.srtlen—计算字符串长度

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	char arr1[] = "abc";
	char arr2[] = { 'a','b','c'};
	printf("%d\n", strlen(arr1));//输出为3 ( \0 ) 不计为字符串长度
	printf("%d\n", strlen(arr2));//输出为42,不是3是因为读完c后,后面有一些随机值被读取,因为没有\0结束标志所以会继续读取。
    //如果回答,第一个 3   第二个  随机值
    //如果arr2定义为 { 'a','b','c','\0'};则也是3
	return 0;
}

strlen不会将\0计入字符长度。

20.转义字符–把原来的意思转变了

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	printf("abcn");//会打印出abcn
	return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	printf("abc\n");//此时只会打印abc,因为\n是一个转义字符,意思为换行。上面\0 是字符串读取的中止标志是一样的转义字符
	return 0;
}
//    \加一些字符有一些特殊作用,称为转义字符 除了上面的\n  \0  还有\t--水平制表符   【在\t的位置加上一个tab大小的空】  空格只是一个字符  tab是一段字符
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	printf("c:\test\32\tect.c");//此时打印出来并不是我们想要的内容,是因为\加一些字符被识别成了转义字符。
	return 0;  
    //  c:\\test\\32\\tect.c   如果改成这个样子,那么\\t表示我将\t中的\转义成了普通\,而不是转义字符中的\
    //   \\用于表示一个反斜杠,防止它被解释为一个转义序列符
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	printf("%c\n",''');//此时会报错,因为前两个''是括字符串的 而里面又是空的,那么我们只需要'\''这样写就可以打印出'了。\'让他变成了一个普通的'。一个字符
	return 0;
}//   \'   \"也是转义字符。\'用于表示字符常量'         \"用于表示一个字符串内部的双引号

image-20221011114543087

21.选择语句if,else

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	int input = 0;
	printf("会好好学习吗,会请输入1;不会请输入0.>:");
	scanf("%d",&input);//&去地址,%d以十进制打印符号整数,scanf输入函数
	if (input == 1)
	{
		printf("好工作\n");
	}
	else//else是其他的意思,如果你不输入if定义的1,那么无论你输入什么都会得到farmer。
        //但我们也可以不写else,写两个if也是可以的。如果输入两个if定义以外的就不会有输出。
	{
		printf("farmer\n");
	}
	return 0;
}

22.循环语句

while循环

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	int line = 0;
	while (line < 5)//while循环语句
	{
		line++;//行数加一,一开始设定行数是0,如果去掉这个,那么会陷入死循环打印"代码".虽然输出代码有很多"行",但真正的行数还是为0(开启显示行数就知道了),所以要加line++
		printf("代码\n");//如果要显示行数则改为 printf("代码:%d\n",line);
	}
	if (line >= 5)
		printf("good job\n");//这个if后可加{}可不加
}

易错点:while语句不加;且要花括号.

do-while循环

image-20221014202127065

#include<stdio.h>
int main(void)
{
	int line = 0;
	do
	{
		line++;
		printf("代码\n");
	} while (line < 5);
	if (line >= 5)
		printf("good job\n");
	return 0;
}

上述while循环的代码转换为do-while如上所示。

for循环

image-20221014210347827

image-20221014210422537

for(1;2;3)1是初始条件,2是循环继续的条件,3是每一轮循环要做的事情(变量作运算来调整循环)。

且for循环的每一个表达式都是可以省略的,for( ;条件; )==while(条件)。

#include<stdio.h>
int main(void)
{
	int line = 0;

	for (line = 0; line < 5; line++)
		printf("代码\n");
	
	if (line >= 5)
		printf("good job\n");
    
	return 0;
}

for循环转换上述代码如上所示。

选用循环语句:

  1. 如果有固定循环次数,用for。
  2. 如果必须先执行一次循环体再循环,用do-while。
  3. 其他情况用while。

23.函数

一.自定义函数

在使用自定义函数时,要把函数定义写在所有使用函数地方的前面。

且自定义函数有声明和定义,两个要一致。

需要说明的是:每个函数有自己的变量空间,参数也位于这个独立的空间,与其他函数没有关系。

用下面的代码进一步说明

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h> 
void swap(int a, int b);//参数

int main()
{
	int a = 5;
	int b = 6;
	swap(a, b);//值
	printf("a=%d b=%d\n", a, b);

	return 0;

}

void swap(int a, int b)//参数
{
	int t = a;
	a = b;
	b = t;
}

这个函数不能交换出a b的值,main中的a和b和swap中的int a int b除了传递值外没有任何关系。swap中的a,b和main中的a,b没有任何关系,更不相等。

image-20221024133514027

#include<stdio.h>
int add(int x, int y)
{
	int z = x + y;
	return z;
}
//上面称为函数体。
//这个add就是自定义函数,意义:用于定义一些反复使用的方法,例如上面举例的相加,当然还有更复杂的。
//简化代码,代码复用。
-------------------------------------------------------------------------------------
int main(void)
{
	int a = 10;
	int b = 20;
	int sum = 0;
	sum = add(a, b);
	printf("sum =%d\n", sum);
	return 0;
}

以下面这段代码来进行自定义函数转换。(代码复制是代码质量低的一种体现)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	int i;
	int sum;

	for (i = 1, sum = 0; i <= 10; i++) {
		sum += i;
	}
	printf("1到10的和是%d\n", sum);
	for (i = 20, sum = 0; i <= 30; i++) {
		sum += i;
	}
	printf("20到30的和是%d\n", sum);
	return 0;

}

转换结果如下

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void sum(int begin, int end)//函数头
//(int begin,int end)是参数表
//sum是函数名
//void是返回类型-没有,就是说sum函数不返回任何东西。
//{}内是函数体
{

	int i;
	int sum = 0;
	for (i = begin; i <= end; i++)
	{
		sum += i;
	}
	printf("从 %d到 %d的和是 % d\n",begin, end, i);

}
int main(void)
{
	sum(10, 20);//函数知道每一次是哪里调用它,会返回到正确的地方。
	sum(20, 30);//第一个sum执行完返回到第二个sum,再返回到return 0;
    
	return 0;

}

上面是void类型的,那我们下面再跑一个int类型的。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int bj(int a,int b)
{
	int max;
	if (a > b)
	{
		max = a;
	}
	else {
		max = b;
	}
    
	return max;//void换成int,表明bj这个函数要返回一个int类型的值,即max。

}

int main(void)
{
	int end;
	end = bj(20, 30);
	printf("%d\n", end);
	return 0;
}

调用函数时给的值必须要和参数的类型匹配,虽然编译器会帮你转换好,但结果可能不是你想要的,C中不严格,C++/Java这方面严格。

同样的,这里面也有return的作用,在下节会讲。

当我们需要调用函数时,需要注意几点:

  1. 函数名(参数值);
  2. ()起到了表示函数调用的重要作用
  3. 即使没有参数也需要()
  4. 如果有参数,则需要给出正确的数量和顺序
  5. 这些值会被按照顺序以此用来初始化函数中的参数

圆括号()

自定义函数时,如果圆括号内不填写任何东西,则不代表没有参数,只是表示这个自定义函数的参数不知道。

那么编译器遇到swap(a,b)时会猜测参数是什么类型

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h> 
void swap();

int main()
{
	int a = 5;
	int b = 6;
	swap(a, b);
	printf("a=%d b=%d\n", a, b);

	return 0;

}

void swap(int a, int b)
{
	int t = a;
	a = b;
	b = t;
}

当然这里没有任何问题,如果把swap定义中的换成void swap(double a,double b)

那结果就会有偏差。

还有就是main函数的圆括号。

以后我们就不止会用到main函数,有时会需要main函数返回一个值,而main(void)表示main不返回任何值。

二.库函数

常用的头文件有**<ctype.h>** <time.h> <stdio.h> <stdlib.h> <math.h> <string.h>

每个头文件中都包含着不同的库函数。详情移步----------->:C语言标准库函数大全

24.return

return停止函数的执行,并送回一个值。

return;

return 表达式;

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int bj(int a,int b)
{
	int max;
	if (a > b)
	{
		max = a;
	}
	else {
		max = b;
	}
	

	return max;//可以把这个值传递给变量,或者函数,也可以丢掉(没有把这个值给任何东西)
    //函数要单一出口,虽然多个return不会报错,但是不好维护,所以最好单一出口.

}

int main(void)
{
	int end;
	end = bj(20, 30);//上面bj中的return max;送回max这个值就是在这里体现,把送回的max赋给end,打印end就是sum的值
	printf("%d\n", end);//即bj(20,30) = 30
	return 0;
}

如果函数有返回值,则必须使用带值的return。

没有返回值的函数

  • void 函数名(参数表)
  • 不能使用带值的return
  • 可以没有return
  • 调用的时候不能做返回值的赋值

25.数组

一.数组的定义

一组相同类型元素的集合。

<类型>变量名称[元素数量];//元素数量是整数。

eg:

int grades[100];

double weight[20];

#include<stdio.h>
int main(void)
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//定义一个存放10个整型的数组.
	float arr2[2];//定义一个存放2个浮点型的数组.
	char ch[3];//定义一个存放3个字符的数组.
	return 0;
}

二.数组的特点

  1. 其中所有的元素具有相同的数据类型(int,double等)。
  2. 一旦创建,不能改变大小。
  3. 数组中的元素在内存中是连续依次排列的。

三.数组的使用

如上 int arr[10] = …

其中的 1,2,3,4,5,6,7,8,9,10其实是有下标的,如下

​ 0,1,2,3,4,5,6,7,8,9

这个下标是编译时机器识别的序号。

而编译器和运行环境都不会检查数组下标是否越界,无论对数组单元做读还是写。所以一旦程序运行,越界的数组访问可能造成问题,导致程序崩溃。所以要保证程序只使用有效的下标值。

有效的下标范围[0,数组的大小-1]

#include<stdio.h>
int main(void)
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n",arr[4]);//数组的下标默认从0开始,打印数组中下标为4的数,那么就是5。
	return 0;
}

代码跑起来打印出来的是5.


那么再与while循环语句结合一下

#include<stdio.h>
int main(void)
{
	int i = 0;
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	while (i < 10)
	{
		printf("%d\n", arr[i]);//此处的i还是数组下标,因为arr中10的下标为9(<10),所以可以打印10
		i++;
	}
	return 0;
}

数组应用

输入数,计算出平均数并给出大于平均数的数。的代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	int x;
	double sum = 0;
	int cnt = 0;
	int number[100];//定义数组
	scanf("%d", &x);
	while (x != 1)
	{
		number[cnt] = x;//对数组中的元素赋值
		sum += x;
		cnt++;
		scanf("%d", &x);
	}
	if(cnt>0)
	{
		int i;
		double average = sum / cnt;
		for (i = 0; i < cnt; i++)
		{
			if(number[i]>average)//使用数组中的元素
			{
			 printf("%d", number[i]);
			}//遍历数组
		}
	}
	return 0;
}

但这个代码有安全隐患,如果cnt超过数组的大小就会有隐患。

26.操作符(简单介绍)

一.算数操作符

+ - * / %


前四个是加减乘除,不作过多赘述。

%是取模,例如

#include<stdio.h>
int main(void)
{
	int a = 5%2;
	printf("%d\n", a);
	return 0;
}

5➗2 = 2…1 余数为1,

那么5%2=1。

二.移(二进制)位操作符


<<左移 >>右移

#include<stdio.h>
int main(void)
{
	int a = 1;
	int b = a << 1;
	printf("%d\n", b);
	return 0;
}

整型1占4个字节,也就是32个bit位,也就是0000000000000…0001.

如果把1左移一个(二进制)位–b,成为0000000000000…0010.(想象32个bit位是一个框,左移最左边的0出去了,然后右边空出自动补0).

那么再以十进制打印b的话就会打印出2.

所以上述代码打印出的是2


#include<stdio.h>
int main(void)
{
	int a = 1;
	int b = a << 2;
	printf("%d\n", b);
	return 0;
}

同样,如果左移两个(二进制)位。b就是0000000000000…0100.

也就是二进制100打印输出为十进制数,也就是4.

三.(二进制)位操作符

&按位与 |按位或 ^按位异或


&按位与

#include<stdio.h>
int main(void)
{
	int a = 3;
	int b = 5;
	int c = a & b;
	printf("%d\n", c);
	return 0;
}

代码跑起来输出结果为1.

3的二进制数是011,5的二进制数是101.

011

101

001(结果)

按位与的运算法则就是,对位有0就得0,两个1才为1.

001为二进制数,转化为十进制仍然为1.


|按位或

#include<stdio.h>
int main(void)
{
	int a = 3;
	int b = 5;
	int c = a|b;
	printf("%d\n", c);
	return 0;
}

输出结果为7.

011

101

111(结果)

按位或的运算法则就是,对位只要有1,那么结果就为1.

二进制数111转化为十进制为7.


^按位异或

#include<stdio.h>
int main(void)
{
	int a = 3;
	int b = 5;
	int c = a^b;
	printf("%d\n", c);
	return 0;
}

输出结果为6.

011

101

110(结果)

按位或与的运算法则就是,对位的二进制位相同则为0,二进制位相异则为1.(二进制位就是0和1)

二进制数110转化为十进制数为6.

四.赋值操作符

= += -= *= /= &= |= ^= >>= <<=

#include<stdio.h>
int main(void)
{
	int a = 10;
	a = 20;//需要说明的是, = 是复制,== 判断相等.
		a = a + 10;
		a += 10;//这两种写法是等价的
    
		a = a & 10;
		a &= 10;//等价
	return 0;
}

其他的以此类推.

五.单目操作符

image-20221011210846847

除了单目操作符还有双目操作符,三目操作符。

例如a+b。 +是一个双目操作符,因为它有两个操作数。


! 逻辑取反操作

#include<stdio.h>
int main(void)
{
	int a = 10;
	printf("%d\n", a);//打印出10
	printf("%d\n", !a);//打印出0
	return 0;
}

在C语言中,0定义为假,非0为真。逻辑取反操作就是让假为真,真为假。

那么10是非0,为真,逻辑取反操作后就为假,即为0.


sizeof

sizeof 计算变量/类型所占空间的大小,单位是字节.

#include<stdio.h>
int main(void)
{
	int a = 10;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(int));
    printf("%d\n", sizeof a);
    printf("%d\n", sizeof int)://这种写法是错误的.
	return 0;
}

如上,我们给出了四行printf。第一二三行是正确的,第四行是错误的。

sizeof在计算变量所占空间的大小时,可以省略().而计算类型所占空间大小时不能省略.

第一行,第二行的结果是一样的.(int类型普遍占4个字节)


与数组结合

#include<stdio.h>
int main(void)
{
	int arr[10] = { 0 };//10个整型元素的数组。1个整型4个字节。
	printf("%d\n", sizeof(arr));
}

格式化输出为40.

#include<stdio.h>
int main(void)
{
	int arr[10] = { 0 };
	int number = 0;
	number = sizeof(arr) / sizeof(arr[0]);
	printf("number =%d\n", number);
}

上为计算数组内元素个数的方法,用数组大小除以元素大小(同类型元素大小相同,而数组是相同类型元素的集合).

输出为10.

++和–的前置与后置

设变量a。

++a是先执行a = a+1,然后再使用a。

a++是先使用a,再执行a = a+1。

–同原理


image-20221015132031122

27.格式字符

image-20221014120006854

28.关系运算符

image-20221014193757929



image-20221015132318000

image-20221015132251524


image-20221014194223203


实例

image-20221014201237180

29.逻辑运算

image-20221015142650692

如果要表达数学中的区间 x∈(4,6).那么不能写成4<x<6.

这样写c语言会先将4<x看成一个逻辑运算,结果是0或1。

不论结果是0还是1都是小于6的,所以最后结果是1.

正确写法应为:x>4&&x<6.

下面看一些例子

image-20221015143220929

1.20<age<30

2.小于0或大于99

3.虽然逻辑运算符优先级小于比较运算符,但!是单目运算符,单目运算符优先级高于双目运算符。

所以!age先处理,结果为1或0,然后再与20比较。整个表达式是1.(若要先处理age<20,则要加括号).


整体优先级:!>&&>||


image-20221015152745984

30.switch-case(多分支处理代替if else)

image-20221015181211904

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	int type = 0;
	scanf("%d", &type);
	if (type == 1)
		printf("你好");
	else if (type == 2)
		printf("早上好");
    else
        printf("what?");
    
	return 0;
}

转换为switch-case

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	int type;
	scanf("%d",&type);
    
	switch (type) {                
	case 1:printf("你好"); break;
	case 2:printf("早上好"); break;
    default:printf("what?");break;
            
    }
	return 0;
}

有几点需要说明的是

  1. break是c语言中的一个关键字,在这里专门用于跳出switch语句。所谓“跳出”,是指一旦遇到 break,就不再执行 switch 中的任何语句,包括当前分支中的语句和其他分支中的语句;也就是说,整个 switch 执行结束了,接着会执行整个 switch 后面的代码。
  2. 如果直到最后一个“整型数值n”都没有找到相等的值,那么就执行 default 后的“语句 n+1”。
  3. 当和某个整型数值匹配成功后,会执行该分支以及后面所有分支的语句。
  4. 由于 default 是最后一个分支,匹配后不会再执行其他分支,所以也可以不添加break;语句。
  5. case 后面必须是一个整数,或者是结果为整数的表达式,但不能包含任何变量。
  6. default 不是必须的。当没有 default 时,如果所有 case 都匹配失败,那么就什么都不执行。

在循环中,有两个词组是经常用到的

  1. break,跳出循环。
  2. continue,跳过循环这一轮剩下的语句进入下一轮。

31.嵌套循环

下面是用 1角 2角 5角 得到x元的程序

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)

{
	int x;
	int one, two, five;
	

	scanf("%d", &x);
	for (one = 1; one < x * 10; one++) 
    {
		for (two = 1;two < x * 10 / 2; two++) 
         {
			for (five = 1; five < x * 10 / 5; five++)
             {
				if (one + two * 2 + five * 5 == x * 10)
                 {
					printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n", one, two, five, x);		
				}
			}
		}
	}
    
	return 0;
}


他可以罗列出所有可能,但如果我们只要他输出一种的话就要跳出这个嵌套的循环。

如果光用一个break加在printf后面那是不行的。

因为break和continue都只能跳出他所在的循环,也就是说如果放break只能跳出第三个for循环,第一个和第二个for循环仍然进行。

所以我们可以接力break,如下:

接力break

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	int x;
	int one, two, five;
	int exit=0;
	

	scanf("%d", &x);
	for (one = 1; one < x * 10; one++)
    {
		for (two = 1;two < x * 10 / 2; two++)
        {
			for (five = 1; five < x * 10 / 5; five++) 
            {
				if (one + two * 2 + five * 5 == x * 10) 
                {
					printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n", one, two, five, x);
					exit = 1;
					break;
				
			    }
		    }if (exit == 1)break;
	    }if (exit == 1)break;
	}
	return 0;

}

加一个exit变量,在得到一个结果赋予他1,然后在第一个for第二个for循环末接上if-break。

还有一种更简单的方式goto out,如下:

goto out

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	int x;
	int one, two, five;
	

	scanf("%d", &x);
	for (one = 1; one < x * 10; one++) {
		for (two = 1;two < x * 10 / 2; two++) 
		{
			for (five = 1; five < x * 10 / 5; five++) 
			{
				if (one + two * 2 + five * 5 == x * 10) 
				{
					printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n", one, two, five, x);
					goto out;
				
				}
			}
		}
	}
	out:
	return 0;

}

goto out 顾名思义 去到out的地方 ,out的地方用 out:来代替。

这种方法虽然看起来好,但是goto out是臭名昭著的。

因为goto 语句是在源码级上的跳转,这使其招致了不好的声誉。若一个程序总是从一个地方跳
到另一个地方,还有什么办法能识别程序的控制流程呢?随着 Edsger Dijkstra 著名的《Goto
considered harmful》论文的出版,众人开始痛斥 goto 的不是,甚至建议从关键字集合中扫
地出门。

所以尽量不要使用goto out,仅在break和continue需要用来跳出嵌套循环时再使用它。

32.system

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdlib.h>
int main(void)
{
	system("calc");
	return 0;
}

system用于打开系统应用,calc是计算器,那么这个程序运行后就会打开计算器。

需要注意的是system所对应的头文件是<stdlib.h>.

33.本地变量(自动变量)

  • 函数的每次运行,就产生了一个独行的变量空间,在这个空间中的变量,是函数的这次运行所独有的,称作本地变量

  • 定义在函数内部的变量就是本地变量

  • 参数也是本地变量

  • 对于本地变量来说,生存期和作用域是一样的:大括号内–块

  • 本地变量是定义在块内的,这个块可以是函数的块内也可以是语句的块内

  • 程序运行进入这个块之前,其中的变量不存在,离开这个块,其中的变量就消失了

  • 块外面定义的变量在块里面仍然有效

  • 块里面定义了和外面同名的变量则掩盖了外面的(全局变量和局部变量)

  • 不能再同一个块内定义同名的变量

  • 本地变量不会被默认初始化

  • 参数在进入函数的时候被初始化了(调用函数的时候,一定要给参数对应的值,那个值会在进入函数时被用来初始化函数)

    #define _CRT_SECURE_NO_WARNINGS 1
    #include <stdio.h> 
    
    int main()
    
    {
    
    int a;
    
    int b;
    
    scanf("%d %d",&a,&b)
    
    if(a<b)
    
    {
    
    int i =10;//i只在块里面
    
    }
    
    i++;//这里的i会显示未被声明,i只在块里面
    
    }
    

一.生存期

什么时候这个变量开始出现了,到什么时候它消亡了

称为自动变量是因为生存期是自动的。

二.作用域

前面也提到,在代码的什么范围内可以访问这个变量(这个变量可以起作用)

下面用代码来进一步说明

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h> 
void swap(int a, int b);//参数

int main()
{
	int a = 5;
	int b = 6;
	swap(a, b);//从这里开始就进入到下面的swap的变量空间,做完swap里的代码后,swap的变量空间就消失了,再调用时才会出现。
	printf("a=%d b=%d\n", a, b);

	return 0;

}

void swap(int a, int b)//参数
{
	int t = a;//swap变量空间中的a,b,t是swap自己的,和main里的a,b没有关系,无论怎么赋值,main中的ab都不会被影响
	a = b;
	b = t;
}

小技巧:

  1. alt+方向键 可以把一行代码向上移或者向下移。
  2. alt+caps+a 鼠标左键拉选要修改的连续行的同一列 或者 按住鼠标滚轮拉选要修改的连续行的同一列。

杂记:

每次召唤rand()就得到一个随机的整数。

x%n的结果是[0,n-1]的一个整数

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值