1.
解析:全选
2.
解析:A.当内存空间释放后,指针将指向其他的区域,成为野指针
3.
解析:B,assert只会在调试模式(debug)下使用,release不会使用
4.
解析:
A:错误,一个函数只能返回一个结果
B:正确,将形参存在数组中,修改数组中内容,可以通过数组将修改结果带出去
C:正确,形参如果用指针,最终指向的是外部的实参,在函数中对指向指向内容进行修改,改变的就是外部的实参
D:正确,全局变量不受函数的结束而结束,在函数中改变全局变量,主调函数中可以看到改变之后的结果
因此,选择A
5.
解析:
A:正确,形参按照值的方式传递,将来形参就是实参的一份临时拷贝,修改形参不会影响外部的实参
B:正确,形参按照指针方式传递,将来形参就是实参地址的一份拷贝,形参指向的是实参,修改形参指针指向的内容, 就是在操作实参
C:错误,C语言中,函数不能嵌套定义
D:正确,函数可以嵌套调用,即:A()中调用B(),B()中调用A(),但是要控制好,否则就成为无限递归
因此,选择C
6.下面代码关于数组名的描述,不正确的
int main()
{
int arr[10] = {0};
return 0;
}
解析:A选项错误明显。arr的类型是int [10],而&arr的类型是int (*)[10],根本不是一个类型,不可能是一样的。而在 sizeof(arr)和&arr中,arr都是看成整体的,而一般它代表一个数组的首地址。
7.下面哪个选项错误
#include <stdio.h>
int main()
{
int *p = NULL;
int arr[10] = {0};
return 0;
}
解析:D.就数据类型来看,A左右两边都是int *,B左右两边都是 int (*)[10],C左右两边都是int *,D左边是 int *,右边是 int (*)[10],故选D。
8.
#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
//在这里完成代码
// 分析:因为数组中存储的元素类型是int类型的,因此只要给一个int的指针,依次取索引数组中的每个元素即可
int* p = arr; // 数组名代表数组首元素的地址
for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i)
{
printf("%d ", *p); // *p: 取到p所指向位置的元素
++p; // 获取p的下一个位置
}
return 0;
}
9.
/*
思路:
遍历数组,对数组中相邻的两个元素进行比较,如果需要升序,前一个数据大于后一个数据时,交换两个位置上的数据,直到所有的数据比较完,此时,最大的数据已经放在数组的末尾。
除最大数据已经排好序外,其余数据还是无需,对剩余数据采用与上述类似的方式进行处理即可
*/
void BubbleSort(int array[], int size)
{
// 外层循环控制冒泡排序的趟数
// size-1表示:最后一趟区间中只剩余1个元素,该趟冒泡可以省略
for(int i = 0; i < size-1; ++i)
{
// 具体冒泡的方式:用相邻的两个元素进行比较,前一个大于后一个元素时,交换着两个数据,依次直到数组的末尾
for(int j = 1; j < size-i; ++j)
{
if(array[j-1] > array[j])
{
int temp = array[j-1];
array[j-1] = array[j];
array[j] = temp;
}
}
}
}
/*
优化:如果某次冒泡结束后,序列已经有序了,后面剩余元素的冒泡可以省略
*/
void BubbleSort(int array[], int size)
{
// 外层循环控制冒泡排序的趟数
// size-1表示:最后一趟区间中只剩余1个元素,该趟冒泡可以省略
for(int i = 0; i < size-1; ++i)
{
int isChange = 0;
// 具体冒泡的方式:用相邻的两个元素进行比较,前一个大于后一个元素时,交换着两个数据,依次直到数组的末尾
for(int j = 1; j < size-i; ++j)
{
if(array[j-1] > array[j])
{
int temp = array[j-1];
array[j-1] = array[j];
array[j] = temp;
isChange = 1; // 如果本次冒泡进行数据交换了,说明本次还是无序的,就将isChange设置为1
}
}
// 如果本次冒泡中,元素没有交换,则本次开始冒泡时,数据已经有序了,后面的冒泡可以不用进行了
if(!isChange)
return;
}
}
10.
解析:
A:错误,二级指针是指针,不能说起比一级指针大,只能说二级指针指向的空间中存储的也是一个地址
B:正确
C:错误,数组的地址一般用一级指针存储,或者用数组指针接收
D:二级指针是指针,但是否占4个字节不一定,要看具体的系统
因此:选择B
11.
/*
思路:该题比较简单,参考代码
*/
size_t my_strlen (const char * str)
{
const char *eos = str;
while( *eos++ ) ;
return( eos - str - 1 );
}
12.
/*
思路:
1. 给定两个下标left和right,left放在数组的起始位置,right放在数组中最后一个元素的位置
2. 循环进行一下操作
a. 如果left和right表示的区间[left, right]有效,进行b,否则结束循环
b. left从前往后找,找到一个偶数后停止
c. right从后往前找,找到一个奇数后停止
d. 如果left和right都找到了对应的数据,则交换,继续a,
*/
void swap_arr(int arr[], int sz)
{
int left = 0;
int right = sz-1;
int tmp = 0;
while(left<right)
{
// 从前往后,找到一个偶数,找到后停止
while((left<right)&&(arr[left]%2==1))
{
left++;
}
// 从后往前找,找一个奇数,找到后停止
while((left<right)&& (arr[right]%2==0))
{
right--;
}
// 如果偶数和奇数都找到,交换这两个数据的位置
// 然后继续找,直到两个指针相遇
if(left<right)
{
tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}
}
}
13.
解析:题目要int的指针数组,A为int数组,B为int数组的指针,C为int的指针数组,D为int(*)(int)函数指针的数组,故选C
14.
解析:
指针数组是一个数组,该数组的每个元素是一个指针
A:正确,定义了一个数组,该数组中有10个元素,每个元素都是int*的指针类型
B:错误,编译失败,定义数组时,要给出空间的大小,如果没有给时,必须要给出初始化结果
C:错误,定义了一个二级指针
D:错误,*和arr先结合,说明arr不是数组。实际上arr是一个指针,一个指向数组的指针。
因此:选择A
15.
解析:
A选项目前还没学,目前只需要了解free不会更改指针的指向。
B选项强调了32位系统,所以没问题。
CD选项是定义本身。
所以排除法也可以确定是A。
16.
解析:
双引号引起来的这一段是一个常量字符串,本质是一个常量字符数组类型,赋给一个指针,相当于把一个数组的首地址赋给指针,即第一个元素h的地址。
只有选项C提到了第一个字符的地址,故选C
17.代码执行结果
#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
char *str3 = "hello bit.";
char *str4 = "hello bit.";
if(str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if(str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
解析:str1和str2是两个数组,数组的操作方式是将右边常量字符串的内容拷贝进来,所以他们是两个空间,只是内容相同,所以str1 != str2。而str3和str4是两个指针,编译器在处理的时候,会将相同的常量字符串做成同一个地址,所以,str3和str4指向的是同一个常量字符串,所以str3 == str4,故选C。
18.
解析:AD缩句后分别是:指针是数组、数组是指针,自相矛盾。B选项说的有问题,数组指针存放的是数组的地址,而非数组本身。故选C。
19.
解析:
A是二级指针数组,B是指针数组,C是char *数组的指针,D是char *的数组。只有C是数组指针。
tip:根据优先级看只有C选项优先跟*结合,其他都不是指针,所以直接选C。
20.
解析:ABD没有区别,加的括号没有影响任何优先级,都是返回值为int *的函数,故选C。
21.
解析:CD前半句压根就不是定义而是声明,A选项参数列表的第二个参数错了。应为char *,B选项正确。需要说明的是,对于函数名来说,前面的&和*都会被忽略,所以fun前面加不加取地址都没区别。
22.
解析:首先C压根就不是函数指针,先排除,然后D返回值不是int,排除,A的参数不是int *,排除,剩下B了。
23.
解析:D类型不完整先排除,然后看返回值,B的返回值是int,C的返回值是int *,故选A。判断返回值类型只需要删掉函数名/函数指针和参数列表再看就行了。int (*(*F)(int, int))(int)删掉(*F)(int, int)后剩下int (*)(int),符合题意。
24.
本题当然可以将所有旋转后的结果放到一个数组里,然后进行查找,但是这种做法既不好操作,也太费事,但是这题有一个很简单的做法:
其实ABCDE无论怎么旋,旋转后的所有结果,都包含在了ABCDEABCD这个字符串里了。
所以做法很简单,只需要将原字符串再来一遍接在后面,然后找一找待查找的字符串是不是两倍原字符串的子集即可。
int findRound(const char * src, char * find)
{
char tmp[256] = { 0 }; //用一个辅助空间将原字符串做成两倍原字符串
strcpy(tmp, src); //先拷贝一遍
strcat(tmp, src); //再连接一遍
return strstr(tmp, find) != NULL; //看看找不找得到
}
25.
我们仔细分析,不难发现,对于杨氏矩阵老说,右上角和左下角的元素是有特点的。右上角的元素是一行中最大的,一列中最小的。左下角的元素是一行中最小的,是一列中最大的。所以我们可以从右上角或者左下角开始查找。比如:从右上角开始查找的时候,右上角的元素比我们要查找元素小,我们就可以去掉右上角元素所在的这一行;右上角的元素比我们要查找的元素大,我们就可以去掉右上角元素所在的这一列。然后依然找右上角的元素继续和要查找的元素与比较。这样每一次比较去掉一行或者去掉一列。这个查找效率是高于遍历数组元素的,所以时间复杂度是小于O(N),也满足题目要求。
#include <stdio.h>
int findnum(int a[][3], int x, int y, int f) //第一个参数的类型需要调整
{
int i = 0, j = y - 1; //从右上角开始遍历
while (j >= 0 && i < x)
{
if (a[i][j] < f) //比我大就向下
{
i++;
}
else if (a[i][j] > f) //比我小就向左
{
j--;
}
else
{
return 1;
}
}
return 0;
}
int main()
{
int a[][3] = { {1, 3, 5},
{3, 5, 7},
{5, 7, 9} }; //一个示例
if (findnum(a, 3, 3, 2))
{
printf("It has been found!\n");
}
else
{
printf("It hasn't been found!\n");
}
return 0;
}
26.
#include<stdio.h>
int main()
{
int killer = 0;
//分别假设凶手是a,b,c,d,看谁是凶手时满足3个人说了真话,一个人说了假话
for (killer = 'a'; killer <= 'd'; killer++)
{
if ((killer != 'a') + (killer == 'c') + (killer == 'd') + (killer != 'd') == 3)
printf("凶手是:%c", killer);
}
return 0;
}
27.
由于此题要打印整个杨辉三角的数据而非取出某一项,所以不可避免的一定是要填出每一项,没有偷懒的余地,那就老老实实的根据规律填空即可。按照题设的场景,能发现数字规律为:d[i][j] = d[i - 1][j] + d[i - 1][j - 1]。所以我们只要按照这个方法填表即可。
void yangHuiTriangle(int n)
{
int data[30][30] = { 1 }; //第一行直接填好,播下种子
int i, j;
for (i = 1; i < n; i++) //从第二行开始填
{
data[i][0] = 1; //每行的第一列都没有区别,直接给1,保证不会越界。
for (j = 1; j <= i; j++) //从第二列开始填
{
data[i][j] = data[i - 1][j] + data[i - 1][j - 1]; //递推方程
}
}
for (i = 0; i < n; i++) //填完打印
{
for (j = 0; j <= i; j++)
{
printf("%d ", data[i][j]);
}
putchar('\n');
}
}
改进:
由于我在填第n行的杨辉三角时,只跟第n-1行的杨辉三角产生联系,不会跟之前的有联系,所以没必要保存每一行的杨辉三角,填一行打一行就行了,这样能让空间复杂度从n^2降低到n。但是在填数据的时候不能对之前的数据覆盖,所以需要从后向前填。而填杨辉三角顺序对结果是没有影响的,所以可以实现。
void yangHuiTriangle(int n)
{
int data[30] = { 1 };
int i, j;
printf("1\n"); //第一行就直接打印了
for (i = 1; i < n; i++) //从第二行开始
{
for (j = i; j > 0; j--) //从后向前填,避免上一行的数据在使用前就被覆盖
{
data[j] += data[j - 1]; //公式同上,由于变成了一维,公式也变简单了。
}
for (j = 0; j <= i; j++) //这一行填完就直接打印了。
{
printf("%d ", data[j]);
}
putchar('\n');
}
}
※这种方法虽然降低了空间复杂度,但只能保存最后一行的数据,不利于反复查询,两个填法各有各的适用场景。就本题而言,改进后的胜出。