Linux C 编程学习第七天_字符串和多维数组_多维字符数组应用-剪刀石头布游戏
字符串
说实话我以前一直搞不懂这个玩意和字符还有数组之间的关系,每次串口通信的时候都要调试很久,各种接收发送乱码,都是因为数据不匹配或者转换出错。
字符串可以看作一个数组," hello world ! \n "
存储方式就像数组一样,也可以使用角标单独访问某个字符,如:
1 char a = "Hello world ! \n "[2];
虽然可以进行访问,但是不允许通过角标更改字符。
因为字符是只读的,不允许修改,这是和数组完全不同的。但是我们可以定义一个字符数组:
初始化方式:
char str[] = "Hello World ! "
这是一个数组,里面元素为 一个个字符,这样的字符数组是可以进行更改的,并且以 '\0' 结尾,也可以叫做字符串。
其实硬要解释的话,字符串和以字符为元素的数组都可以称为字符串。
可以使用printf函数输出:
多维数组
结构体可以嵌套,数组也一样,我们可以定义一个数组的元素是数组,这样就获得了多维数组。
定义一个二维数组:
这里说明,3 表示该数组有 3 个元素,2表示、每一个元素是大小为 2 的数组,没有被初始化的数字为0
所以这个二维数组有3个数组,a[0] a[1] a[2],每个数组都有2个元素,分别是{ 1,2 }、{ 3,4 }、{ 5,0 }
这六个元素在存储器中依然是连续存储的,像一维数组一样,这种存储方式称为Row-major方式,另外有些语言是;一列一列接起来拼起一串存储的,称为Column-major方式。
二位数组初始化也可以这样,这样看的更加好区分
第一维度的长度可以不指定,但是其余的长度都必须指定。
1 #include <stdio.h> 2 3 char str[] = "Hello World !"; 4 char a[][15] = { 5 "", 6 "Hello World !", 7 "yes!", 8 "no", 9 }; 10 11 int main(int argc, char const *argv[]) 12 { 13 printf("%s\n", a[1]); 14 printf("%s\n", str); 15 return 0; 16 }
先前说的字符数组,在这里同样适用。
这样的方法可以代替 switch 语句,用下标访问数组,可以节省很多case分支,尤其事case分支里有重复操作的情况,这样做可以提取公因式。
这种方法称为数据驱动的编程(Data-driven Programming)。
尝试写一个剪刀石头布的代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 5 char str[] = "Hello! let's paly !"; 6 char a[][15] = {"you lose !", "you win !", "Draw !"}; 7 char str1[][20] = {"剪刀", "石头", "布"}; 8 int b[] = {1, 0, 2, 1, 0}; 9 10 int player = 0,cumputer = 0; 11 12 void windows_cmd_support_utf8(void) 13 { 14 #ifdef WIN32 15 system("chcp 65001 & cls"); //cls 用来清除 chcp 的输出 16 #endif 17 } 18 19 int main(int argc, char const *argv[]) 20 { 21 windows_cmd_support_utf8(); 22 srand(time(NULL)); 23 printf("%s\n", str); 24 int goon = 0; 25 26 while(1) 27 { 28 cumputer = rand() % 3; 29 printf("请输入0,1,2分别代表剪刀,石头,布:\n"); 30 scanf("%d", &player); 31 int i =b[(player - cumputer)+2]; 32 printf("电脑出的是:%s\n你出的是:%s\n", str1[cumputer], str1[player]); 33 printf("%s\n", a[i]); 34 } 35 36 return 0; 37 }
我尽力避免使用了 if 这样的语句,疯狂调用数组,突然发现,数组真的是太好玩了,不过相对的这样的写法就比 if 不直观,先看看运行,然后我在解释:
首先我定义了几个字符串数组,用来存储输出的字符串:
这样输出的时候就可以直接调用字符串数组,为了把一样的类型存储在一起,我将它们列成二维字符串数组。
接着先对石头剪刀布进行分析,我和机器人最多只能出 3 种可能,分别是:0,1,2,用我的输入数字减去计算机的输入。
分别列举出来:
赢的情况有:1,-2,平局:0;输:-1,2
给所有数值加上2得到:赢:3,0;平局:2;输:1,4;
刚好复合一个数组的角标,0,1,2,3,4,那么我就创建一个数组,用来对应字符串数组的输出:
这里的1,0,2,1,0,实际上是为了对应字符串数组:
我用 b[ ] 数组的值作为了 a[ ][ ] 数组的角标,那么就可以得到对应输出:
同样,我将玩家输入的数,和电脑生成的伪随机数也坐为字符串数组str1[ ] 的角标,顺便输出对应的情况,看的更加直观。
要是我一个一个去定义字符串是十分麻烦的,但是采用字符串多维数组,就十分方便,同时上述代码没有使用 if 语句坐为判断,其实还是有点不严谨的,因为如果在程序中输入了其他非0,1,2的字符,就会出现奇奇怪怪的结果,或者卡死,应该在代码前加上判断输入的语句的,看了还是避免不了 if 啊~
扯远了,其实在这边是想说一个有意思的东西,那就是“(man - computer + 4) % 3 - 1”思路。
借用流浪的牙膏皮的博客:
man 和computer的取值只能是0 1 2,那么
man - computer 的结果可以是1,-2 0 -1,2
(man赢的取值是1,-2 平的取值是0,输的取值是-1,2)
加上4之后可以是 5,2(赢) 4(平) 3,6(输)
对3进行取余后只有 2(赢) 1(平) 0(输)
再减1 最后只有 1(赢) 0(平) -1 (输)
我认为编此程序 首先分析出 man - computer 的结果可以是1,-2 0 -1,2
其中(man赢的取值是1,-2 平的取值是0,输的取值是-1,2)
利用一些数学表达式运算 把这三类区别开就可以,不一定拘泥在“(man - computer + 4) % 3 - 1”之上。
http://blog.sina.com.cn/s/blog_3eb222740100krz3.html,若有侵权,实属抱歉,马上删除。
我是在研究这个思路的时候,突然想到加 2 刚好是角标,才那么写的,所以其实有很多方法,像上述,加4并且给3取余数之后,省下了0,1,2,这样更好,又可以写成一个新的数组角标,比我前面写的1 0 2 1 0数组更小了,也可以达到同样的效果。
这章更多是学习了字符数组,和多维字符数组的应用。