C语言——查漏补缺

前言

本篇博客主要记录一些C语言的遗漏点,完成查漏补缺的工作,如果读者感兴趣,可以看看下面的内容。都是一些小点,下面进入正文部分。

1. 字符汇聚

编写代码,演示多个字符从两端移动,向中间汇聚

#include <stdio.h>
#include<windows.h>
int main()
{
	char arr1[] = "welcome to bit...";
	char arr2[] = "#################";
	int left = 0;
	int right = strlen(arr1) - 1;
	printf("%s\n", arr2);
	while (left <= right)
	{
		Sleep(1000);
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		left++;
		right--;
		system("cls");
		printf("%s\n", arr2);
	}
	return 0;
}

​

这道题比较简单,其中Sleep是控制其打印的速率的,system是用来清理屏幕的。

2. 二分查找

这是一种常见的,并且效率不错的一种查找方式。但是大家要注意,这种方法只适用于顺序的数字序列,如果是乱序的,这个方法就不合适了。

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int left = 0;
	int right = sizeof(arr) / sizeof(arr[0]) - 1;
	int key = 7;//要找的数字 
	int mid = 0;//记录中间元素的下标 
	int find = 0;
	while (left <= right)
	{
		mid = (left + right) / 2;
		if (arr[mid] > key)
		{
			right = mid - 1;
		}
		else if (arr[mid] < key)
		{
			left = mid + 1;
		}
		else
		{
			find = 1;
			break;
		}
	}
	if (1 == find)
		printf("找到了,下标是%d\n", mid);
	else
		printf("找不到\n");
	return 0;
}

3. 猜数字游戏

写⼀个猜数字游戏 游戏要求:

  1. 电脑⾃动⽣成1~100的随机数

  2. 玩家猜数字,猜数字的过程中,根据猜测数据的大小给出大了或小了的反馈,直到猜对,游戏结束

3.1 随机数的生成

3.1.1 rand

C语言提供了⼀个函数叫rand,这函数是可以生成随机数的,函数原型如下所示:

int rand (void);

rand函数会返回⼀个伪随机数,这个随机数的范围是在0~RAND_MAX之间,这个RAND_MAX的大小是依赖编译器上实现的,但是⼤部分编译器上是32767。

rand函数的使用需要包含⼀个头文件是:stdlib.h

那我们就测试⼀下rand函数,这⾥多调用几次,产生5个随机数:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	printf("%d\n", rand());
	printf("%d\n", rand());
	printf("%d\n", rand());
	printf("%d\n", rand());
	printf("%d\n", rand());
	return 0;
}

我们可以看到虽然⼀次运行中产⽣的5个数字是相对随机的,但是下⼀次运行程序生成的结果和上⼀次⼀模⼀样,这就说明有点问题。 如果再深⼊了解⼀下,我们就不难发现,其实rand函数生成的随机数是伪随机的,伪随机数不是真正的随机数,是通过某种算法生成的随机数。真正的随机数的是无法预测下⼀个值是多少的。而rand函 数是对⼀个叫"种子"的基准值进行运算生成的随机数。 之所以前⾯每次运⾏程序产⽣的随机数序列是⼀样的,那是因为rand函数⽣成随机数的默认种子是1;如果要生成不同的随机数,就要让种子是变化的

3.1.2 srand

C语言中又提供了⼀个函数叫srand,用来初始化随机数的生成器的,srand的原型如下:

void srand (unsigned int seed);

程序中在调用rand函数之前先调⽤srand函数,通过srand函数的参数seed来设置rand函数生成随 机数的时候的种子,只要种子在变化,每次⽣成的随机数序列也就变化起来了。 那也就是说给srand的种子是如果是随机的,rand就能生成随机数;在⽣成随机数的时候⼜需要⼀个随机数,这就矛盾了

3.1.3 time

在程序中我们⼀般是使⽤程序运行的时间作为种子的,因为时间时刻在发生变化的。 在C语言中有⼀个函数叫time,就可以获得这个时间,time函数原型如下:

time_t time (time_t* timer);

time函数会返回当前的日历时间,其实返回的是1970年1⽉1⽇0时0分0秒到现在程序运行时间之间的差值,单位是秒。返回的类型是time_t类型的,time_t类型本质上其实就是32位或者64位的整型类型。

time函数的参数timer如果是非NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。 如果timer是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。

time函数的时候需要包含头文件:time.h

那我们就可以让生成随机数的代码改写成如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
 //使⽤time函数的返回值设置种⼦ 
 //因为srand的参数是unsigned int类型,我们将time函数的返回值强制类型转换 
 srand((unsigned int)time(NULL));
 printf("%d\n", rand());
 printf("%d\n", rand());
 printf("%d\n", rand());
 return 0;
}

3.1.4 设置随机数的范围

所以如果要生成a~b的随机数,方法如下:

a + rand()%(b-a+1)

3.2 代码实现

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void game()
{
 int r = rand()%100+1;
 int guess= 0;
 while(1)
 {
 printf("请猜数字>:");
 scanf("%d", &guess);
 if(guess < r)
 {
 printf("猜⼩了\n");
 }
 else if(guess > r)
 {
 printf("猜⼤了\n");
 }
 else
 {
 printf("恭喜你,猜对了\n");
 break;
 }
 } 
}
void menu()
{
 printf("***********************\n");
 printf("****** 1. play ******\n");
 printf("****** 0. exit ******\n");
 printf("***********************\n");
}
int main()
{
 int input = 0;
 srand((unsigned int)time(NULL));
 do
 {
 menu();
 printf("请选择:>");
 scanf("%d", &input);
 switch(input)
 {
 case 1:
 game();
 break;
 case 0:
 printf("游戏结束\n");
 break;
 default:
 printf("选择错误,重新选择\n");
 break;
 }
 }while(input);
 return 0;
}

4. 一道坑题

这道题大家可以自己先做一下,然后可以在VS上运行验证一下;

C语言中,0为假,非0即为真。

全局变量,没有给初始值时,编译其会默认将其初始化为0。

i的初始值为0,i--结果-1,i为整型,sizeof(i)求i类型大小是4,按照此分析来看,结果应该选择B,但是sizeof的返回值类型实际为无符号整形,因此编译器会自动将左侧i自动转换为无符号整形的数据,-1对应的无符号整形是一个非常大的数字,超过4或者8,故实际应该选择A

这道题其实很隐蔽,真是虾仁猪心!!!

5. 表达式求值

5.1 整型提升

C语言中整型算术运算总是至少以缺省整型类型的精度来进行的。

为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。

整型提升的意义:

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度⼀般就是int的字节长度,同时也是CPU的通⽤寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。 通用CPU(general-purposeCPU)是难以直接实现两个8⽐特字节直接相加运算(虽然机器指令中 可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。

//实例1 
char a,b,c;
...
a = b + c;

b和c的值被提升为普通整型,然后再执行加法运算。

加法运算完成之后,结果将被截断,然后再存储于a中。

如何进行整体提升呢?

  1. 有符号整数提升是按照变量的数据类型的符号位来提升的

  2. 无符号整数提升,高位补0

    //负数的整形提升
    char c1 = -1;
    变量c1的⼆进制位(补码)中只有8个⽐特位:
    1111111
    因为 char 为有符号的 char
    所以整形提升的时候,⾼位补充符号位,即为1
    提升之后的结果是:
    11111111111111111111111111111111
    //正数的整形提升
    char c2 = 1;
    变量c2的⼆进制位(补码)中只有8个⽐特位:
    00000001
    因为 char 为有符号的 char
    所以整形提升的时候,⾼位补充符号位,即为0
    提升之后的结果是:
    00000000000000000000000000000001
    //⽆符号整形提升,⾼位补0

5.2 算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中⼀个操作数的转换为另⼀个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。

​
1 long double
2 double
3 float
4 unsigned long int
5 long int
6 unsigned int
7 int

​
相关推荐
酷讯网络_2408701601 分钟前
【全开源】Java多语言tiktok跨境商城TikTok内嵌商城送搭建教程
java·开发语言·开源
海威的技术博客29 分钟前
JS中的原型与原型链
开发语言·javascript·原型模式
WPG大大通36 分钟前
基于DIODES AP43781+PI3USB31531+PI3DPX1207C的USB-C PD& Video 之全功能显示器连接端口方案
c语言·开发语言·计算机外设·开发板·电源·大大通
从以前1 小时前
【算法题解】Bindian 山丘信号问题(E. Bindian Signaling)
开发语言·python·算法
high20111 小时前
【Java 基础】-- ArrayList 和 Linkedlist
java·开发语言
1nullptr1 小时前
lua和C API库一些记录
开发语言·lua
Jerry Nan1 小时前
Lua元表
开发语言·lua
?333331 小时前
CTFHub Web进阶-PHP-Bypass disable_function攻略
开发语言·安全·web安全·php
所以经济危机就是没有新技术拉动增长了1 小时前
二、javascript的进阶知识
开发语言·javascript·ecmascript