一.练习题
1.写一段代码要求实现一个整型有序数组的二分查找
有bug的代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<windows.h>
int function(int arr[], int k){
int left = 0;
int right = (sizeof(arr) / sizeof(arr[0])) - 1;
while (left<=right){
int mid = (left + right) / 2;
if (arr[mid] < k){
left = mid + 1;
}
else if (arr[mid]>k){
right = mid - 1;
}
else{
return mid;
}
}
return -1;
}
int main(void){
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int k = 7;
int ret = function(arr,k);
if (ret == -1){
printf("无法找到指定数字!\n\a");
}
else{
printf("找到该数字,数组下标为%d\n",ret);
}
system("pause");
return 0;
}
我们先看代码的main()函数部分,我们首先创建了一个arr1[]的整型有序数组,数组中存放的是1-10这10个数字,k为我们需要找的数字这里k=7,随后我们声明了变量ret用来接收自定义函数的 function()函数中的返回值,function()函数需要传入两个参数,第一个参数为数组,第二个参数为要查找的数字,当ret等于-1的时候,也就是 function()函数返回-1的时候则代表查找失败,并调用printf()函数提醒用户,否则输出目标元素的下标ret,我们再来看到自定义函数 function()中 函数的形参是 int arr[]与k 用来接收数组与目标数字,由于使用到二分查找法,我们定义最左边的下标为left 最右边的数组我们需要进行计算,我们之前讲过利用sizeof()操作符来计算元素个数,具体代码如下:
int sz = sizeof(arr)/sizeof(arr[0])
原理就是将数组占用内存的总大小计算出来,再除以单个元素的大小就可以得到数组的元素个数,我们声明了一个变量mid,用来计算数组中间下标是多少,也就是 (left+right)/2 随后使用if语句进行判断当arr[mid]的值小于 k 的时候则代表k的值处于 arr[mid] ~ right 之间大大缩小了查找的范围,随后我们将mid+1的值赋给left便于第二次进行查找,如果arr[mid]的值大于 k 则代表 k的值处于 left ~ arr[mid]-1 之间,当以上条件都不满足的时候则有两种可能 1.已经找到了具体的数字 2.目标数字不在该数组内,但是我们在二分查找的外面套了一层循环语句,只有当(left<=right)的时候才能进入循环,这样子上面的else语句对应的只能是情况1 已经找到目标数字,我们这时候只需要使用return语句对 mid 的值进行返回,如果不满足while入口条件则返回-1,代表没有找到目标数字,看似程序好像没什么问题,但是当我们运行的时候却发现,明明7在数组中,但是程序却返回了找不到的提示,如图所示:
当程序运行出现问题或者预期之外的结果时候就是遇到bug了,我们可以按下F10进行调试(当箭头指向函数的时候按下F11才能进入函数,下文就省略了),我们监视三个变量 分别是 left right k ,从调试结果上来看left 与 k 都为我们预期的结果,但是 right 却出现了问题 ,right的值并没有和我们预期的一样计算出数组元素的个数-1 而是变成了 1 这是为什么呢?
原来代码中,这段代码:
int ret = function(arr1,k);
第一个参数 arr1 是传送的数组中第一个元素的地址,也就是本质上传送了一个指针给函数而不是数组,这时候函数的形参
int function(int arr[], int k)
接收的也就是一个指针,我们利用sizeof()操作符去计算指针在32位平台中会得到4,在64位平台中则会得到8,这样一来 4/4=1
了解了错误的原因我们就可以着手修复bug了,既然我们不能在自定义函数中来计算数组的元素个数,那我们为什么不把这段代码放到main()函数中去求呢?然后再将计算结果传递给自定义函数 function()
我们可以将代码改成如下所示:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<windows.h>
int function(int arr[], int k,int sz){
int left = 0;
int right = sz - 1;
while (left<=right){
int mid = (left + right) / 2;
if (arr[mid] < k){
left = mid + 1;
}
else if (arr[mid]>k){
right = mid - 1;
}
else{
return mid;
}
}
return -1;
}
int main(void){
int arr1[] = {1,2,3,4,5,6,7,8,9,10};
int k = 7;
int sz = sizeof(arr1) / sizeof(arr1[0]);
int ret = function(arr1,k,sz);
if (ret == -1){
printf("无法找到指定数字!\n\a");
}
else{
printf("找到该数字,数组下标为%d\n",ret);
}
system("pause");
return 0;
}
我们再在function()函数中写一个形参sz,用来接收数组元素个数,然后将 sz-1 的值赋值给 right 不就可以了,我们在main()函数中也写一段计算数组元素个数的代码即可,然后将其传入function()函数中,这时候我们就可以发现程序能够正常输出结果了,如图所示:
2.写一个函数,每次调用这个函数的时候,变量就会自增1
有问题的代码:
#include<stdio.h>
void add(int *p){
*p++;
}
int main(void){
int num = 0;
add(&num);
printf("num=%d\n",num);
add(&num);
printf("num=%d\n", num);
add(&num);
printf("num=%d\n", num);
return 0;
}
我们创建了一个名为add()的自定义函数,这个函数不需要返回内容,所以我们写成void 表示空,我们将num的地址传入add()函数中,再对指针*p进行解引用操作后进行自增,看似没问题的代码,当我们运行时候却遇到了问题,如图所示:
变量num并未按照我们预期进行自增操作,num的值一直为0,原因是 ++的运算操作符的优先级是高于*p的,所以我们应当将 *p 用()括号括起来,变成:
(*p)++;
就可以了,当我们修改代码以后运行程序,不出我们所料,程序正确的输出了num的值,如图所示:
2023/8/11
王起舟