二分查找 输入输出 字符串相关

二分查找

二分查找是分治算法的一种应用,其应用是在有序数组中查找某个元素的下标。由于其比较次数只有log2nlog_2nlog2n 次,所以速度非常快。

其做法是准备三个下标,分别让start 指向第一个位置, end 指向最后一个位置,然后让 mid 的位置是 两者正中间的位置,随后用中值 mid 所指向位置中的元素和待查找元素比较,如果比其大,则让 end 向前,走到 mid - 1的位置上,如果比其小,则让 start 向后,走到 mid + 1的位置上,如果找到, 则直接返回mid。如果查找中发现 start 和 end 的位置交错了,则表示没找到。

 int binarySearch(int* arr, int n, int f)
 {
 	int start = 0;
 	int end = n - 1;
 	int mid;
 	while (start <= end)
 	{
 		mid = (start + end) / 2;
 		if (arr[mid] < f)
 		{
 			start = mid + 1;
 		}
		 else if (arr[mid] > f)
 		{
 			end = mid - 1;
 		}
 		else
 		{
 			return mid;
 		}
    }
 		return -1;
 }

输入输出缓冲区

在C语言中会提供三个标准输入输出接口,即 stdin 、 stdout 、 stderr ,其中前两个就是我们平时使用的输入输出缓冲区。

1、在一个程序中,所有的输入共享一个输入缓冲区,所有的输出共享一个输出缓冲区。

2、输入时,一旦数据被读走,这些数据就会从输入缓冲区中清理掉,输出时,一旦输出缓冲区被清空, 则这些内容就会被显示在屏幕上。

输出缓冲区

输出缓冲区的输出方式非常简单,就是临时存放所有的待显示数据,在当前的MSVC环境下,会在以下 时机清理输出缓冲区:

1、一个输出语句结束时 2、输出缓冲区溢出时(大小约为1K)

3、程序结束时

但并不是所有环境都遵循以上规则,所以如果需要手动清空输出缓冲区,可以使用fflush(NULL); 来清空。

输入缓冲区

程序会在用户输入完毕敲下回车时,将临时接取的数据放入输入缓冲区,然后由输出缓冲区按照各种规则将数据放入指定的变量。已经成功读走的数据就清理掉了,而没有读走的数据会一直留在缓冲区内。

※由于输入缓冲区的提交规则是敲下回车的那一刻,所以输入缓冲区在处理数据时,最后的那个字符一 定是回车。

输入缓存读取的规则:

1、 %d/%f/%lf

跳过所有的空白字符(空格、回车、\t等),遇到负号或者数字才开始转换,遇到非数字字符停止。如果是%f/%lf ,会允许一个小数点的存在。如果在转换的过程中没有遇到数字字符,则表示转换失败。

2、%c和 getchar

这两个会无条件的从缓存中读取一个字符。无论缓存里有什么,都会读取。

3、%s 跳过所有的空白字符(空格、回车、\t等),遇到可见字符才开始接收,遇到空格或回车时停止。

如果缓冲区中的数据足够读取,则读取函数( scanf 、 getchar 等)不会阻塞,否则就会阻塞程序等待用户输入数据,填充输入缓冲区后再继续向下执行。

如果输入缓存的数据不符和条件(%d/%f/%lf ),导致了转换失败,则 scanf 不会读走这些数据,它们依然留在缓冲区中。但这样处理会导致一个问题,即如下代码:

 while (1)
 {
 	int a;
 	scanf("%d", &a);
     
 	printf("%d\n", a);
 }

此时,这个%d是在循环里的,一旦输入了字母,就会导致缓存中的这个字母永远没有人读走,而导致所有的%d都失败,从而导致死循环的后果。为了规避这件事,可以这样优化代码:

 while (1)
 {
 	int a;
 	int ret = scanf("%d", &a); //接取scanf返回值,判断a是否正确输入

 	if (ret == 0) //如果是0,表示输入异常
	{
		 while ('\n' != getchar()); //通过这样的方式清空输入缓存
		//由于输入缓存的末尾一定是回车,所以通过这样的方式就能清空了
	}
	 else
 	{
 		printf("%d\n", a); //正常的话再打印
	}
 }

字符串

C语言没有原生的字符串类型,C中的字符串就是一串地址连续的字符,即字符数组。C的字符串以一个空字符’\0’(ASCII码值为0)作为字符串的末尾。即没有尾零的字符串是不完整的。

字符串的输入输出

scanf/printf

使用%s可以对字符串进行输入输出,需要的载体是一个数组:

char str[128];

scanf("%s", str); //由于str本身就已经是(隐式转换的)指针了,所以不再需要取地址

printf("%s", str);

注意事项

1、scanf 的%s 碰到空格即结束; 2、scanf 的 %s 没有阻拦机制,即使输入越界也依然可以正常输入,所以之后使用%s一定要加宽度;

3、printf 的 %s 可以使用精度,表示只要前几个字符。

由于%s不能整行读取,为了解决这个问题,就引入了以下两种方法:

1、使用 fgets

可以使用如下方式整行读取:

char str[16];

fgets(str, 15, stdin); //第二个参数相当于宽度,第三个参数固定

※fgets 会将缓存中的回车也一并读取进来。

2、使用**%[]**

这个方式可以在中括号中放入你希望接取的字符有哪些,如:

char str[64];

scanf("%63[a-z]", str);
 		  //此处表示只要小写字母

中括号内可以放入任意你希望接收的字符,如 %[a-zA-Z0-9,.] 就表示所有的大小写字母、数字、逗号和句号都可以读取到,别的不能。

此外,中括号内可以放一个^,表示除了这些都要,如: %[ ^0-9 ] 表示除了数字字符外都要。

所以,可以使用这样的方式来整行接收:

scanf("%63[^\n]", str);

※如果使用这样的方式接收,则回车会留在输入缓存中,如果下次继续使用这个语句(例如在循环里),则会直接跳出。所以,需要使用 getchar 或其他手段(如 %*c )吃到这个回车。

puts

直接打印一个字符串

※puts会自带一个回车。

字符串相关函数

数字处理函数

atoi

头文件: #include <stdlib.h>

函数声明:

int atoi(const char* str);

将一个数字字符构成的字符串转换为 int 类型的整数返回。

同系列函数:

long atol(const char* str);
double atof(const char* str);

※atoi的处理模式和 scanf 的 %d 一致。同理, atof 处理模式和 scanf 的 %lf 一致

字符串基本函数

※这部分的头文件都是 #include <string.h>

strlen

函数声明:

size_t strlen(const char* str);

这个函数可以求出字符串str的有效字符个数(不包含尾零)

strcpy

函数声明:

char* strcpy(char* dst, const char* src);

这个函数可以将src中的字符串复制到dst中(这个函数不会做长度校验,所以需要用户自己在dst中留够位置)

※strcpy会将尾零也一并复制到dst中。

这个函数会将赋值完毕的dst再次返回,以支持嵌套。

strncpy

函数声明:

 char* strncpy(char* dst, const char* src, int n);

这个函数的作用和strcpy类似,但只会将前n个字符拷贝到dst中。如果src的长度不足n,则这个函数就等同于strcpy,否则这个函数是不会自动添加尾零的。

strcat

函数声明:

 char* strcat(char* dst, const char* src);

这个函数可以将src中的字符串复制到dst中字符串的尾部,即将src连接到dst后。函数本身会修改 dst,同时将修改后的dst返回。

由于这个函数同样不会做长度校验,所以更要注意dst的长度问题。

※如果将strcpy看做字符串的赋值运算符,那么strcat就是+=。

strncat

函数声明:

 char* strncat(char* dst, const char* src, int n);

同理,这个函数只会将src中的前n个字符接到dst后。

※注意这个函数是会无条件加尾零的。

strcmp

函数声明:

 int strcmp(const char* str1, const char* str2);

这个函数相当于比较运算符,如果str1比str2大,则返回正数,如果str1比str2小,则返回负数, 如果一样大就返回0。

※字符串判断大小的依据是ASCII码值。比较时会先比较第一个字符的ASCII码值,如果一样就继续向后比较,直到两者分出大小为止。如果完全一样,就返回0。

strncmp

函数声明:

int strncmp(const char* str1, const char* str2, int n);

只比较前n个,即前n个一样就返回0了。

相关函数(MSVC不支持):

strcasecmp
strncasecmp

这两个函数在比较时不区分大小写。

字符串查找函数

※这部分的头文件都是 #include <string.h>

※这些函数的返回值在无法找到时皆会返回空指针,后不再赘述。

strchr

参数列表:

char* strchr(const char* str, char find);

在字符串str中查找 find 字符第一次出现的位置。

strrchr

参数列表:

char* strrchr(const char* str, char find);

在字符串str中查找 find 字符最后一次出现的位置。

strstr

参数列表:

char* strstr(const char* str, const char* find);

在字符串str中查找 find 子串第一次出现的位置。

※子串指的是在原串中任取其中一段所构成的字符串。(自身就是自己的子串,空串是任意字符串的子串)

strpbrk

参数列表:

char* strstr(const char* str, const char* find);

在字符串str中查找 find 字符集中任意字符第一次出现的位置。

内存相关函数

※这部分的头文件都是 #include <string.h>

memset

参数列表:

void* memset(void* ptr, int n, size_t size);

这个函数会将以指针 ptr 指向的位置开始的 size 个字节全部填充成n(实际用的是n的最低字节)

memset 通常用于给一片空间清零:

memset(ptr, 0, 100 * sizeof(int));
memcpy

参数列表:

void* memcpy(void* dst, const void* src, size_t size);

这个函数会将 src 指针中所指向的位置后的 size 个字节全部拷贝到 dst 所指向的位置。

使用示例:

int a[10] = { 9,7,0,1,4,8,5,6,3,2 };
int b[10];

memcpy(b, a, 10 * sizeof(int)); //这里就将数组a中的所有内容拷贝到了数组b中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值