前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C语言指针——练习

C语言指针——练习

作者头像
小李很执着
发布2024-06-15 08:22:51
发布2024-06-15 08:22:51
10100
代码可运行
举报
文章被收录于专栏:学习笔记学习笔记
运行总次数:0
代码可运行

第一题.strlen函数的模拟实现

strlen函数用于计算字符串的长度,以下是一个模拟实现:

代码语言:javascript
代码运行次数:0
运行
复制
int strlen(char *str)
 {
    int len = 0;
    while (*str != '\0')
 {
        len++;
        str++;
 }
    return len;
}

该函数通过一个while循环来遍历字符串,每遍历一个字符,计数器len就加1。当遍历到字符串的结尾字符'\0'时,循环结束,函数返回计数器的值,即字符串的长度。 

第二题 模拟实现strcpy

strcpy是C语言标准库中的函数,用于将字符串复制到另一个字符串中。

以下是模拟实现strcpy的代码:

代码语言:javascript
代码运行次数:0
运行
复制
char* strcpy(char* dest, const char* src) {
    char* p_dest = dest;
    while (*src != '\0') {
        *p_dest++ = *src++;
    }
    *p_dest = '\0'; // 添加字符串结尾符
    return dest;
}

strcpy的工作原理是遍历源字符串,逐个字符地复制到目标字符串中,遇到字符串结尾符\0时停止复制并在目标字符串末尾添加一个\0。在模拟实现中,使用指针p_dest指向目标字符串,每复制一个字符,就将指针后移一位;使用指针src指向源字符串,每读取一个字符,就将指针后移一位。最后返回指向目标字符串的指针dest

第三题.模仿qsort的功能实现一个通用的冒泡排序

代码语言:javascript
代码运行次数:0
运行
复制
void swap(char* buf1, char* buf2, size_t size)
{
	int i = 0;
	for (i = 0; i < size; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}
void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* e1, const void*e2))
{
	//冒泡排序的趟数
	int i = 0;
	for (i = 0; i < num - 1; i++)
	{
		//一趟冒泡排序
		int j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
		
			if(cmp((char*)base + j * size, (char*)base + (j + 1) * size)<0)
			{
				//交换
				swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
			}
		}
	}
}

 第四题.实现一个函数,可以左旋字符串中的k个字符。

例如:ABCD左旋一个字符得到BCDA

           ABCD左旋两个字符得到CDAB

设计循环使其可以旋1次,然后让他执行n次是一个最简单的思路:

代码语言:javascript
代码运行次数:0
运行
复制
void leftRound(char * src, int time)
{
	int i, j, tmp;
  int len = strlen(src);
  time %= len; //长度为5的情况下,旋转6、11、16...次相当于1次,7、12、17...次相当于2次,以此类推。
	for (i = 0; i < time; i++) //执行k次的单次平移
	{
		tmp = src[0];
		for(j = 0; j < len - 1; j++) //单次平移
		{
			src[j] = src[j + 1];
		}
		src[j] = tmp;
	}
}

改进一:

这个思路当然可以,但是一次一次转毕竟太麻烦,就不能一次到位么?

当然可以,我们可以选择拼接法,一次到位:

代码语言:javascript
代码运行次数:0
运行
复制
void leftRound(char * src, int time)
{
	int len = strlen(src);
	int pos = time % len; //断开位置的下标
	char tmp[256] = { 0 }; //更准确的话可以选择malloc len + 1个字节的空间来做这个tmp
	
	strcpy(tmp, src + pos); //先将后面的全部拷过来
	strncat(tmp, src, pos); //然后将前面几个接上
	strcpy(src, tmp); //最后拷回去
}

改进二:

这个方法要用到一个数组形成的辅助空间,让人觉得有点不爽,还可以有更好的选择,例如ABCDEFG,左旋3次后变成DEFGABC,有一个特殊的操作方式:

先将要左旋的前三个家伙逆序(CBADEFG),然后将后半段也逆序(CBAGFED),最后整体逆序(DEFGABC)即可。这样只需要做数值交换即可,可以写一个函数帮我们完成局部逆序,代码如下:

代码语言:javascript
代码运行次数:0
运行
复制
void reverse_part(char *str, int start, int end) //将字符串从start到end这一段逆序
{
	int i, j;
	char tmp;

	for (i = start, j = end; i < j; i++, j--)
	{
		tmp = str[i];
		str[i] = str[j];
		str[j] = tmp;
	}
}

void leftRound(char * src, int time)
{
	int len = strlen(src);
	int pos = time % len;
	reverse_part(src, 0, pos - 1); //逆序前段
	reverse_part(src, pos, len - 1); //逆序后段
	reverse_part(src, 0, len - 1); //整体逆序
}

 第五题.写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。

例如:给定s1 =AABCD和s2 = BCDAA,返回1

给定s1=abcd和s2=ACBD,返回0.

AABCD左旋一个字符得到ABCDA

AABCD左旋两个字符得到BCDAA

AABCD右旋一个字符得到DAABC

解析:

本题当然可以将所有旋转后的结果放到一个数组里,然后进行查找,但是这种做法既不好操作,也太费事,但是这题有一个很简单的做法:

其实ABCDE无论怎么旋,旋转后的所有结果,都包含在了ABCDEABCD这个字符串里了。

所以做法很简单,只需要将原字符串再来一遍接在后面,然后找一找待查找的字符串是不是两倍原字符串的子集即可。

代码语言:javascript
代码运行次数:0
运行
复制
int findRound(const char * src, char * find)
{
	char tmp[256] = { 0 }; //用一个辅助空间将原字符串做成两倍原字符串
	strcpy(tmp, src); //先拷贝一遍
	strcat(tmp, src); //再连接一遍
	return strstr(tmp, find) != NULL; //看看找不找得到
}

方法二

代码语言:javascript
代码运行次数:0
运行
复制
int is_left_move(char* str1, char* str2)
{
	int len1 = strlen(str1);
	int len2 = strlen(str2);
	if (len1 != len2)
		return 0;

	strncat(str1, str1, len1);
	if (strstr(str1, str2) == NULL)
		return 0;
	else
		return 1;
}

int main()
{
	char arr1[20] = "abcdef";//abcdefabcdef
	//bcdefa
	//cdefab
	//defabc
	//efabcd
	//fabcde
	//abcdef
	char arr2[] = "cdef";

	int ret = is_left_move(arr1, arr2);//判断arr2是否是arr1旋转所得

	if (ret == 1)
		printf("Yes\n");
	else
		printf("No\n");

	return 0;
}

第六题.杨氏矩阵

有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。

要求:时间复杂度小于O(N);

代码语言:javascript
代码运行次数:0
运行
复制
#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;
}

方法二,可返回所求值的坐标

代码语言:javascript
代码运行次数:0
运行
复制
int Find(int arr[3][3], int *px, int *py, int k)
{
	int x = 0;
	int y = *py - 1;

	while (x <= *px - 1 && y >= 0)
	{
		if (arr[x][y] < k)
		{
			x++;
		}
		else if (arr[x][y] > k)
		{
			y--;
		}
		else
		{
			*px = x; 
			*py = y;
			return 1;
		}
	}
	*px = -1;
	*py = -1;
	return 0;
}

int main()
{
	int arr[3][3] = { 1,2,3, 4,5,6, 7,8,9 };
	int k = 0;
	int x = 3;
	int y = 3;
	scanf("%d", &k);//7
	int ret = Find(arr, &x, &y, k);//存在返回1,如果不存在返回0
	if (ret == 1)
	{
		printf("Yes\n");
		printf("%d %d\n", x, y);
	}
	else
	{
		printf("No\n");
		printf("%d %d\n", x, y);
	}
		

	return 0;
}

第七题.下面程序的结果是:( )

int main() {   int aa[2][5] = {10,9,8,7,6,5,4,3,2,1};   int *ptr1 = (int *)(&aa + 1);   int *ptr2 = (int *)(*(aa + 1));   printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));   return 0; } A.1, 6 B.10, 5 C.10, 1 D.1, 5

 &aa的类型是int (*)[2][5],加一操作会导致跳转一个int [2][5]的长度,直接跑到刚好越界的位置。减一以后回到最后一个位置1处。*(aa + 1)相当于aa[1],也就是第二行的首地址,自然是5的位置。减一以后由于多维数组空间的连续性,会回到上一行末尾的6处。故选A。

第八题.模拟实现了二维数组

方法一.静态开辟

代码语言:javascript
代码运行次数:0
运行
复制
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };

	int* arr[3] = {arr1, arr2, arr3};

	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			//printf("%d ", *(arr[i] + j));
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

方法二.动态开辟

代码语言:javascript
代码运行次数:0
运行
复制
#include <stdlib.h>
//
int main()
{
	
	int **arr = (int**)malloc(3*sizeof(int*));

	int i = 0;
	for (i = 0; i < 3; i++)
	{
		*(arr + i) = (int*)malloc(5*sizeof(int));
	}
	//初始化
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			arr[i][j] = 1;
		}
	}
	//打印
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}

	//释放
	for (i = 0; i < 3; i++)
	{
		free(arr[i]);
	}
	free(arr);
	arr = NULL;

	return 0;
}

第六题.

代码语言:javascript
代码运行次数:0
运行
复制
/int main()
//{
//	int a[5] = { 1, 2, 3, 4, 5 };
//	int* ptr = (int*)(&a + 1);
//	printf("%d, %d", *(a + 1), *(ptr - 1));
//
//	return 0;
//}

第七题 

代码语言:javascript
代码运行次数:0
运行
复制
//由于还没学习结构体,这里告知结构体的大小是20个字节
//X86 环境下演示
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
} * p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
//0x开头的数字是16进制的数字
int main()
{
	p = (struct Test*)0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);

	return 0;
}

第八题 

代码语言:javascript
代码运行次数:0
运行
复制
#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]);//?
	return 0;
}

int a[3][2] = { (0, 1), (2, 3), (4, 5) };//实际初始化为1 3 5,为逗号表达式取两者中的最大值

第九题 

代码语言:javascript
代码运行次数:0
运行
复制
int main()
{
	int a[5][5];
	int(*p)[4];//数组指针
	p = a; 
	printf("%p, %d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	//

	//
	return 0;
}

//a - int(*)[5]     //p - int(*)[4]    

//%p是打印地址,认为内存中存储的补码就是地址

第十题

代码语言:javascript
代码运行次数:0
运行
复制
int main()
{
	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int* ptr1 = (int*)(&aa + 1);
	int* ptr2 = (int*)(*(aa + 1));
	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
	return 0;
}

 第十一题

代码语言:javascript
代码运行次数:0
运行
复制
#include <stdio.h>
//阿里的笔试题
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

P++   跳过一个char*的指针

第十二题 

代码语言:javascript
代码运行次数:0
运行
复制
int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;

	printf("%s\n", **++cpp);
	printf("%s\n", *-- * ++cpp + 3);
	printf("%s\n", *cpp[-2] + 3);
	printf("%s\n", cpp[-1][-1] + 1);
	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一题.strlen函数的模拟实现
  • 第二题 模拟实现strcpy
  • 第三题.模仿qsort的功能实现一个通用的冒泡排序
  •  第四题.实现一个函数,可以左旋字符串中的k个字符。
  •  第五题.写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。
  • 第六题.杨氏矩阵
  • 第七题.下面程序的结果是:( )
  • 第八题.模拟实现了二维数组
    • 方法一.静态开辟
    • 方法二.动态开辟
  • 第六题.
  • 第七题 
  • 第八题 
  • 第九题 
  • 第十题
  •  第十一题
  • 第十二题 
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档