c语言基础(三)

204 阅读6分钟

1. extern:

表示声明。 没有内存空间。 不能提升。

2. const:

限定一个变量为只读变量。
const int a = 20;
a = 30; // 表达式必须是可修改的左值

3. volatile:

防止编译器优化代码。
volatile int flg = 0;  
// 猜想在有些硬件中,需要根据内存的值产生相应的状态,如果不加volatile,则被编译器优化之后,最终效果可能和预期不相符合。
int a = 20;
a = 21;
a = 22;
a = 23;
会被优化成:int a = 23;

4. register:

定义一个寄存器变量。没有内存地址。
register int a = 10;
    int b = 20;
    // printf("%d\n", &a); // error: address of register variable 'a' requested
    printf("%d\n", &b);

5. 字符串:

C语言中,用双引号引着的一串字符,称之为字符串。一定有一个结束标记'\0'
char ch = 'A';  一个字节
"abc"  --> 'a''b''c''\0'
'a' 不等价 "a"'a''\0'

6. printf函数:

%s:打印字符串, 挨着从字符串的第一个字符开始打印,打印到'\0'结束。
%d:打印整数
%c:打印字符
%x:打印16进制数
%u:打印无符号
%m.n: 打印实型时用到,一共有 m 位(整数、小数、小数点),n位小数。
%0m.nf: 其中 f:表示打印实型,一共有 m 位(整数、小数、小数点),n位小数。 0:表示不足 m 位时,用0凑够m位。
%%: 显示一个%。 转义字符'\' 对 % 转义无效。
%Ns:显示N个字符的字符串。不足N用空格向左填充。
%0Ns:显示N个字符的字符串。不足N用0向左填充。
%-Ns:显示N个字符的字符串。不足N用空格向右填充。

7. putchar函数:

输出一个 字符 到屏幕。
直接使用 ASCII 码。
不能输出字符串。
'abc'既不是一个有效字符,也不是一个有效字符串。
常用putchar('\n');来打印换行。一定要注意不是putchar("\n");而是putchar('\n');也就是说putchar是将'\n'当成一个字符来看待的。!实践之后感觉putchar('\n');不靠谱。
printf("\n");而这里是"\n"而非'\n';

8. scanf函数:

从键盘接收用户输入:
1. 接收 整数 %d
	int a, b, c;  创建变量空间, 等待接收用户输入。
	scanf("%d %d %d", &a, &b, &c);
2. 接收 字符 %c
	char a, b, c;
	scanf("%c %c %c", &a, &b, &c);
3. 接收 字符串 %s 重要的事情读三遍s! s! s!
	char str[10];	// 定义一个数组,用来接收用户输入的 字符串。
	scanf("%s", str);	// 变量名要取地址传递给 scanf, 数组名本身表示地址,不用 & 符。
            将接受的字符串打印出来的做法是: printf("%s\n", str);

接收字符串:
	1) scanf 具有安全隐患。如果存储空间不足,数据能存储到内存中,但不被保护。【空间不足不要使用】
	2) scanf 函数接收字符串时, 碰到 空格 和 换行 会自动终止。不能使用 scanf 的 %s 接收带有空格的字符串。
    举一个例子:
    如果char str[10];
    而输入为:hello world okk,那么不会报错,但是在使用printf打印的时候,只会打印出hello,因为遇到空格停止了。但是后面的依然存了下来。
    如果char str[10];
    而输入为:helloworldokk,在使用printf打印的时候,会打印出helloworldokk。但是okk是不被保护的!
将 #define _CRT_SECURE_NO_WARNINGS  添加到程序 第一行。 解决scanf 4996错误

9. getchar()函数:

从键盘获取用户输入的 一个字符。
返回该获取的字符的 ASCII 码。
    char t = getchar();
    putchar(t);
    getchar结束的标志是回车。

10. 算数运算符:

先 * / % 后 + -
除法运算后,得到的结果赋值给整型变量时,取整数部分。
除0 :错误操作。不允许。
对0取余:错误操作。不允许。
不允许对小数取余。余数不能是 小数。 35 % 3.4;
对负数取余,结果为余数的绝对值。10 % -3;  --》 1

11. ++ 和 --:

前缀自增、自减:
	先自增/自减, 在取值。
	int a = 10;
	++a;		// a = a+1;
后缀自增、自减:
	int a  = 10;
	a++;		// a = a+1;
	先取值, 再自增/自减。

12. 赋值运算:

int a = 5;
a += 10;  // a = a+10;
a -= 30;  // a = a-30;
a %= 5;	  // a = a % 5;

13. 比较运算符:

== 判等。
!= 不等于.
< 小于
<= 小于等于	
> 大于
>= 大于等于
13 < var < 16; ==> var > 13 && var < 16;

逻辑运算符:

0为假,非0为真。(1)
逻辑非:!  ---> printf("%d\n", !'t'); // 0
	非真为假, 非假为真。
逻辑与: &&(并且)
	同真为真,其余为假。
逻辑或:|| (或)
	有真为真。同假为假。
    
这里强调一下,在for循环中,可以使用复杂的条件作为训话终止的条件,而不是常见的单一条件进行判断。

14. 运算符优先级:

[]() > ++ -- (后缀高于前缀) (强转) sizeof > 算数运算(先乘除取余,后加减)> 
比较运算 > 逻辑运算 > 三目运算(条件运算)> 赋值运算 > 逗号运算	

15. 三目运算符: ? :

表达式1 ? 表达式2 : 表达式3 
    char t = getchar();
    int xx = t == 'a' ? 0 : 1;
表达式1 是一个判别表达式。 
    如果为真。整个三目运算,取值表达式2。
如果为假。整个三目运算,取值表达式3。
默认结合性。自右向左。

16. 类型转换:

隐式类型转换:
	由编译器自动完成。
	由赋值产生的类型转换。 小--》大 没问题。 大 --》 小 有可能发生数据丢失。
	int r = 3;
	float s = 3.14 * r * r;
	321:	256 128 64 32 16 8 4 2 1
		1   0   1  0  0  0 0 0 1 
	char ch  = 0   1  0  0  0 0 0 1 	
强制类型转换:
	语法:	(目标类型)带转换变量
		(目标类型)带转换表达式
	大多数用于函数调用期间,实参给形参传值。

17. if分支语句:匹配一个范围.属于模糊匹配.

if (判别表达式1)
{
	判别表达式为真,执行代码。
}
else if(判别表达式2)
{
	判别表达式1为假,并且判别表达式2,执行代码。
}
else if(判别表达式3)
{
	判别表达式1为假,判别表达式2为假,判别表达式3, 执行代码。
}
...
else
{
	以上所有判断表达式都为假, 执行代码。
}

if练习:

屏幕输入三只小猪的重量。借助if分支语句,找出最重的小猪重量。

18. switch 分支:精确匹配.

// 假如switch中的判别表达式的值来自于getchar,那么就不要想着getchar一个汉字"一" 
switch(判别表达式)
{
	case 1:
		执行语句1break;			// 防止case穿透
	case 2:
		执行语句2;
		break;
	case 3:
		执行语句3;
		break;
	...
	case N:
		执行语句N;
		break;
	default:
		其他情况的统一处理;
		break;
}
case 穿透:
	在一个case分支中如果,没有break;那么它会向下继续执行下一个case分支.

	

19. while循环:

while(条件判别表达式)
{
	循环体.
}

练习:敲7:1--100数数, 逢7和7的倍数,敲桌子。

7的倍数:	num % 7 == 0
个位含7:	num % 10 == 7
十位含7:	num / 10 == 7

20. do while 循环:

无论如何先执行循环体一次。然后在判断是否继续循环。
do {
	循环体
} while (条件判别表达式);

练习:求水仙花数。 一个三位数。各个位上的数字的立方和等于本数字。 234 861

100 -- 999
int num  = 100;
个位数: int a = num % 10;   		a*a*a;
十位数: int b = num / 10 % 10; 
百位数: int c = num / 100;