1.下面关于"指针"的描述不正确的是:( )😁
A.当使用free释放掉一个指针内容后,指针变量的值被置为NULL
B.32位系统下任何类型指针的长度都是4个字节
C.指针的数据类型声明的是指针实际指向内容的数据类型
D.野指针是指向未分配或者已经释放的内存地址
A.我们用malloc申请多少字节的内存空间,使用完我们用free释放空间,但是不会被置为NULL,我们需要手动置为空。 B/C/D正确
2.关于下面代码描述正确的是:( )char* p = "hello bit";😁
A.把字符串hello bit存放在p变量中
B.把字符串hello bit的第一个字符存放在p变量中
C.把字符串hello bit的第一个字符的地址存放在p变量中
D.*p等价于hello bit
C是正确的。D.*p等价于h
3.关于数组指针的描述正确的是:( )😁
A.数组指针是一种数组
B.数组指针是一种存放数组的指针
C.数组指针是一种指针
D.指针数组是一种指向数组的指针
C.正确。D.指针数组是一种指向指针的数组。B.数组指针是一种指向数组的指针。指针不可以存放数组!
4.下面哪个是数组指针( )😁
A.int** arr[10]
B.int (*arr[10])
C.char *(*arr)[10]
D.char(*)arr[10]
C正确。 C.是指针数组指针。A.B.D.由于[]的优先级高于*,所以*arr[],会先和[]结合变成数组,就不是指针了。
5.下面哪个是函数指针?( )😁
A.int* fun(int a, int b);
B.int(*)fun(int a, int b);
C.int (*fun)(int a, int b);
D.(int *)fun(int a, int n);
C正确。 A.是一个函数声明,参数是int,返回类型是int*。B.是一个函数声明,参数是int,返回类型是int*。C.是一个函数指针,*先和fun结合,参数是int,返回类型是int。D.是一个函数声明,参数是int,返回类型是int*。
6.定义一个函数指针,指向的函数有两个int形参并且返回一个函数指针,返回的指针指向一个有一个int形参且返回int的函数?下面哪个是正确的?( )😁
A.int (*(*F)(int, int))(int)
B.int (*F)(int, int)
C.int (*(*F)(int, int))
D.*(*F)(int, int)(int)
对A选项分析:存在*,这是一个指针,指向的是函数F,函数F有两个int形参且返回一个函数指针。返回的指针的类型是:int(*)(int),形参有int,返回int。选A。
7.在游戏设计中,经常会根据不同的游戏状态调用不同的函数,我们可以通过函数指针来实现这一功能,下面哪个是:一个参数为int *,返回值为int的函数指针( )😁
A.int (*fun)(int)
B.int (*fun)(int *)
C.int* fun(int *)
D.int* (*fun)(int *)
8.下面哪个代码是错误的?( )😁
#include <stdio.h> int main() { int *p = NULL; int arr[10] = {0}; return 0; }
A.p = arr;
B.int (*ptr)[10] = &arr;
C.p = &arr[0];
D.p = &arr;
A.arr是数组首元素的地址放到整型指针p中,正确。B.取到数组的地址用数组指针接收,正确。C.取到数组首元素的地址存放到整型指针p中,正确。D.取到数组的地址存放到指针p中,按道理应该存放到数组指针中,所以 D是错误的。但是如果我们非要这么做,编译器也不会报错,只不过会进行一定转换,在语法上当然是错误的。
9.下面代码关于数组名描述不正确的是( )😁
int main() { int arr[10] = {0}; return 0; }
A.数组名arr和&arr是一样的
B.sizeof(arr),arr表示整个数组
C.&arr,arr表示整个数组
D.除了sizeof(arr)和&arr中的数组名,其他地方出现的数组名arr,都是数组首元素的地址。
A.数组名arr是首元素的地址,&arr是数组的地址。 A错误。B/C/D正确。
10.如何定义一个int类型的指针数组,数组元素个数为10个:( )😁
A.int a[10]
B.int (*a)[10]
C.int *a[10];
D.int (*a[10])(int);
A.是一个数组。B.是一个数组指针。C.是一个指针数组。D.是一个函数指针数组,类型为int(*)(int)。所以 C正确
11.设有以下函数void fun(int n,char *s){……},则下面对函数指针的定义和赋值均是正确的是:( )😁
A.void (*pf)(int,char); pf=&fun;
B.void (*pf)(int n,char *s); pf=fun;
C.void *pf(); *pf=fun;
D.void *pf(); pf=fun;
A.函数指针的形参是int和char*,A错误。 B正确。C.D.函数的形参错误,且不是一个指针。
12.杨氏矩阵💡
有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。
要求:时间复杂度小于O(N);
1 2 3
4 5 6
7 8 9
进行分析:1.时间复杂度小于O(N),是我们运行程序进行次数的最坏情况,也就是说当有n个元素时,我们最多查找N次,此时时间复杂度就是O(N)。题目要求小于O(N)2.探寻杨氏矩阵规律:如上图,我们发现右上角的3和左下角的7最特殊。从右上角的3分析,3是这一行最大的元素,3是这一列最小的元素。假如我们需要寻找7是否存在,我们发现7>3,由于3是第一行最大的元素,说明7不在第一行。从第二行开始6是第二行最大的元素,6<7,说明7不在第二行。从第三行开始,7<9,9是第三行最大的元素,说明7在第三行,同时说明7不在第三行的第三列。从第三行的第二列开始,7<8,说明7不在第三行的第二列。从第三行第一列开始,7==7,说明7在第三行的第三列。同样从左下角推理道理相同。3.为什么特殊的元素规律不是1或是9呢?因为假如当我们寻找7时,我们从1的角度分析,7>1,说明7可能在第一行可能在第一列,此时我们无法确定7具体位置,不能进行对行和列的排除。
#include<stdio.h> int Find(int arr[][3],int* r,int* c,int k) { int x = 0; int y = *c - 1; int flag = 0; while (x<=*r-1&&y>=0) { if (arr[x][y] < k) { x++; } else if (arr[x][y] > k) { y--; } else { *r = x; *c = y; flag = 1; return 1; } } if (flag == 0) { return 0; } } int main() { int arr[3][3] = { 1,2,3,4,5,6,7,8,9 }; int k = 7; int x = 3; int y = 3; //int x,int y和函数参数的设计,即实现了输入值也实现了接收返回值。 //由于return只能返回一个值,所以通过指针实现返回值的接收 int ret=Find(arr, &x, &y,k); if (ret == 0) { printf("没找到!\n"); } else { printf("找到了,下标为:[%d][%d]\n", x, y); } return 0; }
13.字符串左旋💡
实现一个函数,可以左旋字符串中的k个字符。
例如:
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
方法一
//字符会不断重复进行移动,效率不是很高 void left_move(char ch[], int k) { int i = 0; int len = strlen(ch); //当旋转次数大于k次,实际进行旋转次数-k次,为防止重复进行: k %= len; //进行k次 for (i = 0; i < k; i++) { //旋转一个字符 //将第一个字符放到tmp中 char tmp = ch[0]; //将\n以及之前的字符向前移动 int j = 0; for (j = 0; j < len - 1; j++) { ch[j] = ch[j + 1]; } //将\n之前的字符覆盖成tmp中存放的最初第一个字符,\n在len-1处,\n之前一个就是len-2 ch[len - 2] = tmp; } } int main() { char ch[COUNT] = { 0 }; printf("请输入字符串:\n"); fgets(ch, sizeof(ch), stdin); int k = 0; printf("请输入左旋字符串个数:\n"); scanf("%d", &k); left_move(ch, k); puts(ch); return 0; }
方法二算法规律:有一个字符串abcdef,逆序两个字符变成cdefab逆序左两个字符:ba cdef逆序右剩余字符:ba fedc整体逆序:cdefab
#include<assert.h> //逆序字符串函数 void reverse(char*left,char*right) { //保证指针有效性 assert(left); assert(right); while (left < right) { char tmp = *left; *left = *right; *right = tmp; left++; right--; } } void left_move(char ch[], int k) { int len = strlen(ch); k %= len; //逆序左,起始为数组首元素地址,逆序k个字符,终止位置是ch+k-1 reverse(ch, ch + k - 1); //逆序右,起始位置是ch+k,终止位置ch+len-1(最后一个元素) reverse(ch+k, ch +len-1); //逆序整体 reverse(ch,ch+len-1); } int main() { char ch[] = "abcdef"; int k = 0; printf("请输入左旋字符串个数:\n"); scanf("%d", &k); left_move(ch, k); puts(ch); return 0; }
14.字符串旋转结果💡
写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。
例如:给定s1 =AABCD和s2 = BCDAA,返回1
给定s1=abcd和s2=ACBD,返回0.
AABCD左旋一个字符得到ABCDA
AABCD左旋两个字符得到BCDAA
AABCD右旋一个字符得到DAABC
//方法一 #include<string.h> #include<assert.h> void reverse(char*left,char*right) { //保证指针有效性 assert(left); assert(right); while (left < right) { char tmp = *left; *left = *right; *right = tmp; left++; right--; } } void left_move(char ch[], int k) { int len = strlen(ch); k %= len; //逆序左 reverse(ch, ch + k - 1); //逆序右 reverse(ch+k, ch +len-1); //逆序整体 reverse(ch,ch+len-1); } int is_left_move(char arr1[],char arr2[]) { int len1 = strlen(arr1); int len2 = strlen(arr2); if (len1 != len2) { return 0; } int i = 0; for (i = 0; i < len1; i++) { left_move(arr1, 1); if (strcmp(arr1, arr2) == 0) { return 1; } } return 0; } int main() { char arr1[]= "AABCD"; char arr2[] = "BCDAA"; int ret=is_left_move(arr1, arr2); if (ret == 1) { printf("YES!\n"); } else { printf("NO\n"); } return 0; }
铺垫三个函数:
int main() { char arr1[20] = "hello "; char arr2[20] = "hello "; //追加字符串,空间够大的前提 strcat(arr1, "world!"); //可控制追加字符串 strncat(arr2, "world!", 3); //在arr1字符串中查找arr2是否存在 //如果存在,则返回arr2在arr1中的位置(地址) //如果不存在,返回空指针(NULL) char*ret=strstr(arr1, arr2); puts(arr1); puts(arr2); if (ret == NULL) { printf("NO!\n"); } else { printf("%s\n", ret); } return 0; }