C语言是一种强类型语言,当使用一种类型的对象代替另外一种类型的对象进行操作时,必须首先进行类型转换。
类型转换的方式,一般可分为隐式类型转换和显示类型转换(也称为强制类型转换)。
隐式类型转换由编译器自动进行,不需要程序员干预。
隐式类型转换的几种情况: 算术运算,赋值,参数传递
在对变量赋值时,若等号两边的数据类型不同,需要把右边表达式的类型转换为左边变量的类型,这可能会导致数据失真(精度降低),所以隐式类型转换不一定是安全的。 运算转换:C语言中不同类型的数据需要转换成同一类型,才可以进行计算。
char -> short -> int -> unsigned int -> long -> unsigned long -> double float -> double
隐式类型转换示例
#includeint main() { int i = -2; unsigned int j = 1; if ( (i + j) >= 0 ) { printf("i+j >= 0\n"); } else { printf("i+j < 0\n"); } printf("i+j=%0X\n", i + j); // FFFFFFFF printf("i+j=%d\n", i + j); // -1 printf("i+j=%u\n", i + j); // 4294967295 // 有符号和无符号类型在内存中的表示都是一样的; // 关键看我们的计算机如何解析; return 0; }
-2 如何表示 +2: 00000000 00000000 00000000 00000010 -2: 11111111 11111111 11111111 11111101 + 1 -2: 11111111 11111111 11111111 11111110 -2: 0xFFFFFFFE +1: 00000000 00000000 00000000 00000001 -2+1: 11111111 11111111 11111111 11111111 0xFFFFFFFF -1 +1 00000000 00000000 00000000 00000001 -1: 11111111 11111111 11111111 11111110 + 1 -1: 11111111 11111111 11111111 11111111 -1: 0xFFFFFFFF printf("%d", i + j); %d: 以int类型打印i+j; 结果是0xFFFFFFFF,被解析为-1 %u: 把-2转为uint,0xFFFFFFFE很大的正数;
以char类型的二进制表示举例
有符号 o----------->-1 0---------->o 范围 -128 -1 0 127 无符号 o----------->127 128---------->o 范围 0 127 128 255
二进制 有符号 无符号 0000 0000 0 0 0000 0001 1 1 0000 0010 2 2 ... 0111 1111 127 127 1000 0000 -128 128 #有符号无符号分离点 1000 0001 -127 129 1000 0010 -126 130 ... 1111 1110 -2 254 1111 1111 -1 255 1 0000 0000 0 0 无符号 0~127,128~255,在255之后发生反转 有符号-128~-1,0~127, 在127之后发生反转
显示类型转换由程序员明确指定,C语言显示类型转换也称为强制类型转换。
强制类型转换语法如下:
(char)num;
这表示把num
变量当char
类型数据使用;
强制类型转换有可能造成问题; C语言中任何数据可以当作任何类型使用,但不建议这么做,要慎用类型转换保证转换是安全有意义的;
/* * 类型转换 */ #includeint main() { printf("大小是%d\n", sizeof(1 ? 1 : 0.9)); //8 printf("大小是%d\n", sizeof(1 ? 1 : 9)); //4 printf("-7 + 3 > 0 is %d\n", -7 + 3 > 0); //0 printf("-7 + 3u > 0 is %d\n", -7 + 3u > 0); //1 printf("(char)300 is %d\n", (char)300); //44 return 0; }
强制类型转换的实现方式是临时生成一个新数据,使用旧数据对新数据进行赋值; 类型转换并不会改变原数据;
int a = 1; (unsigned char)a == 1; (short)a == 1; (int)a == 1;
并不会因为强制类型转换而多读取a所在的存储空间, 只是用原来的数据临时生成了一个新类型的数据供以后解读;
对指针的强制类型转换会影响程序对数据的读取和解析方式;
#includeint main() { char arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; void *p = NULL; p = arr; /* 对指针的强制类型转换会影响程序对数据的读取和解析方式 */ int inta = *(int *)p; short shorta = *(short *)p; char chara = *(char *)p; // 被强制类型转换的数据并没有发生变化 printf("%p, %p, %p\n", (int *)p, (short *)p, (char *)p); // 0x7fff52f3b040, 0x7fff52f3b040, 0x7fff52f3b040 //指针的类型变化,对其解析的方式就会不同,读取对应地址的方式也不同 printf("%x, %x, %x\n", inta, shorta, chara); // 4030201, 201, 1 return 0; }
#includeint main() { char arr[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; void *p = NULL; p = arr; /* 对指针的强制类型转换会影响程序对数据的读取和解析方式 */ printf("%x, %x, %x\n", *(char *)p, *(short *)p, *(int *)p); /* 1, 201, 4030201 */ /* 强制类型转换的实现方式是临时生成一个新数据, */ /* 使用旧数据对新书据进行赋值;以后的操作采用的都是新数据; */ printf("%x, %x, %x\n", (char)arr[0], (short)arr[0], (int)arr[0]); /* 1, 1, 1 */ return 0; }
流程控制语句可以让程序中的语句不再从上到下逐条执行; 言外之意就是程序一般是按照从上到下,顺序执行;
是一种流程控制语句,分支可以把程序中的某些语句忽略掉不去执行;
if
关键字可以用来编写分支语句;if (condition) { sentence; }
if
分支语句中只有当逻辑表达式为真时才会执行对应的所有语句;
如果多个分支的逻辑表达式之间存在互斥关系(任何时候最多只有一个表达式为真),则可以采用else
关键字把他们合并成一个分支语句;
if (condition_1) { sentence; } else if (condition_2) { sentence; }
一个分支语句中的多个逻辑表达式之间如果具有互补关系(任何时候有且只有一个逻辑表达式结果为真),则可以把最后一个逻辑表达式省略;
if (condition_1) { sentence; } else { sentence; }
/* * if分支演示 */ #includeint main() { int num = 0; printf("请输入一个整数"); scanf("%d", &num); if (num > 0) { printf("正数\n"); } else if (num == 0) { printf("零\n"); } else { printf("负数\n"); } return 0; }
/* * 编写程序根据用户给定的年月计算天数 */ #includeint main() { int year, month; printf("请输入年和月"); scanf("%d%d", &year, &month); int day = 0; if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { day = 31; } else if (month == 4 || month == 6 || month == 9 || month == 11) { day = 30; } else if (month == 2) { if (!(year % 400) || (!(year % 4) && year % 100)) { day = 29; } else { day = 28; } } printf("%d年%d月共%d天\n", year, month, day); return 0; }
/* * 编程从键盘得到三个整数,找出其中最大的整数打印在屏幕上 * 要求不使用另外的变量, * 三个变量的内容可以修改但必须保证永远记录用户输入的三个数字 */ #includeint main() { int a = 0, b = 0, c = 0; printf("请输入三个整数: "); scanf("%d%d%d", &a, &b, &c); if (a < b) { a ^= b; //交换 b ^= a; a ^= b; } if (a < c) { a ^= c; //交换 c ^= a; a ^= c; } printf("输入的三个数字为: %d, %d, %d\n", a, b, c); printf("最大数字为: %d\n", a); return 0; }
如果有一组数字,数字的个数有限,每个数字对应一组专门的处理语句; 这种情况的分支可以采用下面的语法实现;
switch ... case
语句也可以用来实现分支这种分支专门用来解决上面提到的情况; 格式:
switch (num) { case 1: ...; case 2: ...; default: ...;//可以省略 }
/* * 季节练习 */ #includeint main() { int season = 0; printf("请输入一个代表季节的数字: "); scanf("%d", &season); switch (season) { case 1: printf("春天\n"); break; case 2: printf("夏天\n"); break; case 3: printf("秋天\n"); break; case 4: printf("冬天\n"); break; default: printf("太任性\n"); break; } return 0; }
也是流程控制语句,它可以让一组语句多次反复执行
for
关键字可以用来编写循环语句for循环的编写步骤:
(循环变量赋值成开始数字; 用逻辑表达式描述循环变量和结束数字的之间的关系; 描述循环变量的变化方式)
在小括号前面加关键字for
; 在小括号后面加入一对大括号,其中包含反复执行的语句;for循环语句中每次循环变量发生变化则大括号里的语句执行一次, 每次大括号里的语句执行时,循环变量都对应范围内的某一个数字; 大括号里的语句负责处理循环变量当前所对应数字的操作; 如:
for (i = 0; i <= 5; i++) { printf("%d", i); }
/* * for循环演示 */ #includeint main() { int num = 0; for (num = 1; num <= 5; num++) { printf("%d ", num); } printf("\n"); return 0; }
/* * for练习 * 编程计算10到50之间所有整数的和 */ #includeint main() { int num = 0, sum = 0; for (num = 10; num <= 50; num++) { sum += num; } printf("sum is %d\n", sum); }
假设有如下循环
for(1; 2; 3){ 4; }
以上循环按照如下分组方式执行:
[1,2] [4,3,2] [4,3,2] [4,3,2] ...
除了第一组以外所有组都一样;for(1-->2<--3){ |\ / | 4; } | quit
/* * 编程从用户给出的数字中,找出最大数, * 要求不使用新变量,单个变量的内容不可以改变 */ #includeint main() { int a = 0, b = 0, c = 0; printf("请输入三个数字: "); scanf("%d%d%d", &a, &b, &c); printf("最大数字为:"); if (a <= b) { if (b <= c) { printf("%d\n", c); } else { printf("%d\n", b); } } else { if (a <= c) { printf("%d\n", c); } else { printf("%d\n", a); } } return 0; }
hh:mm:ss
, hh表示小时数,mm表示分钟数,ss表示秒数/* * 编程根据用户给出的时分秒数据计算出下一秒的数据, * 按如下格式打印在屏幕上: * hh:mm:ss * hh表示小时数,mm表示分钟数,ss表示秒数 */ #includeint main() { int hh, mm, ss; printf("请输入时,分,秒的数字: "); scanf("%d%d%d", &hh, &mm, &ss); /* 第一种方法 */ if (ss == 59) { ss = 0; if (mm == 59) { mm = 0; if (hh == 23) { hh = 0; } else { hh++; } } else { mm++; } } else { ss++; } printf("下一秒的时间是: "); printf("%02d:%02d:%02d\n", hh, mm, ss); /* 第二种方法 */ if (mm == 59 && ss == 59) { hh++; hh %= 24; } if (ss == 59) { mm++; mm %= 60; } ss++; ss %= 60; printf("下一秒的时间是: "); printf("%02d:%02d:%02d\n", hh, mm, ss); return 0; }
/* * 编写程序判断用户给定的非负数是不是素数 * 素数即除了1和它本身之外再没有别的约数 */ #includeint main() { unsigned int num = 0; printf("请输入一个非负数: "); scanf("%d", &num); int i = 0; for (i = 2; i <= num - 1; i++) { if (!(num % i)) { printf("数字%d不是素数(%d)\n", num, i); break; } } if (!(i <= num - 1)) { printf("数字%d是素数\n", num); } return 0; }
/* * 使用循环编程解决砝码逻辑 */ #includeint main() { unsigned int a = 0; printf("请输入重量: "); scanf("%d", &a); int i = 0; for (i = 1; i <= a; i *= 2) { printf("%d\t", i); } printf("\n"); return 0; }
爱我
和不爱我
/* * 编程根据用户给定的花瓣数在屏幕上交替打印爱我和不爱我 */ #includeint main() { int num = 0; printf("请输入花瓣数: "); scanf("%d", &num); for (num; num > 0; num--) { if (num % 2) { printf("爱我\n"); } else { printf("不爱我\n"); } } return 0; }
/* * 使用循环解决鸡兔同笼问题: * 共有40个头,100只脚,计算鸡和兔子分别有多少只 */ #includeint main() { int a = 40, b = 100; int ji = 0, tu = 0; for (ji = 0; ji <= 40; ji++) { tu = 40 - ji; if (ji * 2 + tu * 4 == 100) printf("鸡有%d只,兔子有%d只\n", ji, tu); } return 0; }