C语言学习记录—进阶作业2(字符指针)

1. 下面关于"指针"的描述不正确的是:(   )

A.当使用free释放掉一个指针内容后, 指针变量的值被置为NULL
B.32位系统下任何类型指针的长度都是4个字节
C.指针的数据类型声明的是指针实际指向内容的数据类型
D.野指针是指向未分配或者已经释放的内存地址
答案:A - free只释放空间,不将指针置为NULL
 

2. 关于下面代码描述正确的是:(   )

char* p = "hello bit";
A.把字符串hello bit存放在p变量中
B.把字符串hello bit的第一个字符存放在p变量中
C.把字符串hello bit的第一个字符的地址存放在p变量中
D.*p等价于hello bit
答案:C - p存放的是第一个字符h的地址,*p得到的是字符h,所以选项B、D错
 

3. 关于数组指针的描述正确的是:(    )

A.数组指针是一种数组
B.数组指针是一种存放数组的指针
C.数组指针是一种指针
D.指针数组是一种指向数组的指针
答案:C - 数组指针不存放数组,只存放数组地址。指针数组是数组

4. 下面哪个是数组指针(   )

A.int** arr[10]
B.int(*arr[10])
C.char* (*arr)[10]
D.char(*)arr[10]
答案:C - ABD数组名都先和[]结合,是数组

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 - ABD中fun都先和()结合,是函数

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)(int, int)是一个函数指针且有两个int形参,把这部分去掉还剩返回类型int(*)(int),这个返回类型又是一个函数指针,且形参是int,返回类型是int

7. 在游戏设计中,经常会根据不同的游戏状态调用不同的函数,我们可以通过函数指针来实现这一功能,下面哪个是:一个参数为int * ,返回值为int的函数指针( )

A.int (*fun)(int)
B.int (*fun)(int*)
C.int* fun(int*)
D.int* (*fun)(int*)
答案:B - A形参是int,C是函数,D返回类型是int*
 

8. 下面哪个代码是错误的?()

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;
答案:D - 数组地址要赋给数组指针,p是整形指针

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 - 数组名是首元素地址,&数组名,表示取出整个数组地址

10. 如何定义一个int类型的指针数组,数组元素个数为10个:()

A.int a[10]
B.int(*a)[10]
C.int* a[10];
D.int (*a[10])(int);
答案:C - A是整形数组,B是数组指针,D是函数指针数组(a先和[10]结合,是数组。去掉a[10],剩下的是函数指针)

11. 下面代码的执行结果是( )

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;
}
A.str1and str2 are same str3and str4 are same
B.str1and str2 are same str3and str4 are not same
C.str1and str2 are not same str3and str4 are same
D.str1and str2 are not same str3and str4 are not same
答案:C - str1和str2数组在内存中有各自独立空间,str3和str4指针指向了同一个常量字符串

12. 设有以下函数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;
答案:B - A第二个形参char类型不对;CD pf先和()结合是函数
 

13. 字符串左旋

实现一个函数,可以左旋字符串中的k个字符。
例如:
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
 

思路一:

1. 把要旋转的第一个字符取出放到临时变量中
2. 把剩下字符往前移
3. 重复上述步骤,直到所有字符旋转完毕(要旋转几个字符,就循环几次)

此方法效率较低,越靠后的字符移动频率越高

#include <string.h>
void left_rotate(char arr[], int k)
{
	int i = 0;
	int len = strlen(arr);
	k %= len;//当k>=len时,有些旋转次数是没有意义的(例如len=6,k=7的实际效果其实就旋转
	for (i = 0; i < k; i++)//旋转几个字符就循环几次
	{
		char tmp = arr[0];//把要旋转第一个字符放到临时变量中
		int j = 0;
		for (j = 0; j < len - 1; j++)//把剩下字符往前移,剩下的字符比字符串长度少1
		{
			arr[j] = arr[j + 1];
		}
		arr[len - 1] = tmp;//最后一个位置放存到临时变量中的第一个字符
	}
}
int main()
{
	char arr[] = "abcdef";//不能是字符串常量
	int k = 0;
	scanf("%d", &k);
	left_rotate(arr, k);
	printf("%s\n", arr);
	return 0;
}

思路二:

1. 将要旋转的部分和剩下的部分分别逆序
示例:a b c d e f旋转两个字符,即 b a | f e d c
2. 再将整个字符串逆序 c d e f a b
此方法用到的都是逆序字符串,所以需要一个逆序字符串函数
逆序字符串需要知道起始位置和结束位置

#include <assert.h>
void reverse(char* left, char* right)
{
	assert(left && right);
	while (left < right)
	{
		char tmp = *left;
		*left = *right;
		*right = tmp;
		left++;
		right--;
	}
}
void left_rotate(char arr[], int k)
{
	int len = strlen(arr);
	k %= len;//这里必须处理k,否则会造成越界访问
	reverse(arr, arr + k - 1);//左
	reverse(arr + k, arr + len - 1);//右
	reverse(arr, arr + len - 1);//整体
}
int main()
{
	char arr[] = "abcdef";//不能是字符串常量
	int k = 0;
	scanf("%d", &k);
	left_rotate(arr, k);
	printf("%s\n", arr);
	return 0;
}

14. 杨氏矩阵

可以理解为二维数组。有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。
要求:时间复杂度小于O(N);
1 2 3
4 5 6
7 8 9
时间复杂度O(N) - 如果有n个元素,找一个元素最坏的情况需要n次才能找到

思路:
用二维数组最右上角的元素和被查找元素比较,这样可以快速的筛选掉一行或一列

方法一:传值调用

int find_num(int arr[3][3], int r, int c, int k)//此函数只能提示是否找到,但不提供被查找元素的坐标
{
	//找到最右上角元素
	int x = 0;
	int y = c - 1;

	while (x<=r-1 && y>=0)
	{
		if (k < arr[x][y])//被查找数比最右上角元素小,说明不在最后一列,列要前移
		{
			y--;
		}
		else if (k > arr[x][y])//被查找数比最右上角元素大,说明不在第一行,行要下移
		{
			x++;
		}
		else
		{
			//printf("%d %d\n", x, y);//这种提供坐标方式不好,因为只是打印了坐标,却没有真正提供坐标
			return 1;
		}
	}
	return 0;//找不到
}
int main()
{
	int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
	int k = 0;
	scanf("%d", &k);

	//行和列的传值调用
	int ret = find_num(arr, 3, 3, k);
	printf("%d\n", ret);

	return 0;
}

方法二:结构体返回坐标

struct Point 
{
	int x;
	int y;
};
struct Point find_num(int arr[3][3], int r, int c, int k)
{
	int x = 0;
	int y = c - 1;
	struct Point p = { -1,-1 };
	while (x <= r - 1 && y >= 0)
	{
		if (k < arr[x][y])//被查找数比最右上角元素小,说明不在最后一列,列要前移
		{
			y--;
		}
		else if (k > arr[x][y])//被查找数比最右上角元素大,说明不在第一行,行要下移
		{
			x++;
		}
		else
		{
			p.x = x;
			p.y = y;
			return p;
		}
	}
	return p;//找不到
}
int main()
{
	int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
	int k = 0;
	scanf("%d", &k);

	//使用结构体作为返回值
	struct Point ret = find_num(arr, 3, 3, k);
	printf("%d %d\n", ret.x, ret.y);
	return 0;
}

方法三:返回型参数

void find_num(int arr[3][3], int* pa, int* pb, int k)
{
	//找到最右上角元素
	//*pa和*pb是数组实际的行和列,x和y是数组下标
	int x = 0;//行
	int y = *pb - 1;//列

	while (x <= *pa - 1 && y >= 0)
	{
		if (k < arr[x][y])//被查找数比最右上角元素小,说明不在最后一列,列要前移
		{
			y--;
		}
		else if (k > arr[x][y])//被查找数比最右上角元素大,说明不在第一行,行要下移
		{
			x++;
		}
		else
		{
			*pa = x;
			*pb = y;
			return;
		}
	}
	*pa = -1;
	*pb = -1;
}
int main()
{
	int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
	int k = 0;
	scanf("%d", &k);

	//行和列的传址调用
	//注意此方法每次调用前,都要将a和b的值重置为3。因为上一次调用时a和b的值被修改了
	int a = 3;//行
	int b = 3;//列
	int ret = find_num(arr, &a, &b, k);
	if (ret == 1)
		printf("%d %d\n", a, b);
	else
		printf("找不到\n");

	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值