二分查找
二分查找是分治算法的一种应用,其应用是在有序数组中查找某个元素的下标。由于其比较次数只有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中。

1万+

被折叠的 条评论
为什么被折叠?



