37.C语言进阶(纯干货) — 练习 && 解释

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

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是整形指针,所以error

2.下列代码输出什么呢?

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;
}

result:二和三

解释:一和二是数组名,数组名是表示首元素的地址,并且一和二会开辟两个不同的空间,那么它们的地址自然就不相同啦~;         三和四是常量字符串,常量字符串相同不会存两份的,所以它们是相同的(现在VS2019打常量字符串都是必须加const的哦!)

3.杨氏矩阵

题目内容:
有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的(没说是等差递增哦)
请编写程序再这样的矩阵种查找某个数字是否存在
要求 : 时间复杂度小于O(N);    O(N) = 假设数组有N个元素,那么查找的次数最坏的情况下是N次

思路:

矩阵例子:

1 2 3


4 5 6
7 8 9

会发现每行的最后一个元素是最大的,那么要找的数字可以直接和最后一个元素对比,如果比它大就跳过,比它小就再这行里用列找即可。或者用一列里最大的来比,小的就在这一列里用行找。

代码实现:

​
int find_num(int arr[3][3], int r, int c, int k)
{
	int x = 0;
	int y = c - 1;

	while (x < r && y >= 0)
	{
		if (arr[x][y] < k)
		{
			x++;
		}
		else if (arr[x][y] > k)
		{
			y--;
		}
		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 = 7;
	//如果找不到返回1,找不到返回0
	int ret = find_num(arr, 3, 3, k);
	if (ret == 1)
	{
		printf("找到了\n");
	}
	else
	{
		printf("找不到了\n");
	}

	//查找一个数字
	//不满足时间复杂度小于O(N)
	//int i = 0;
	//int j = 0;
	//for (i = 0;i < 3;i++)
	//{
	//	for (j = 0;j < 3;j++)
	//	{
	//		if (arr[i][j] == 7)
	//		{
	//			//....
	//		}
	//	}
	//}

	return 0;
}

​

可以find_num不是用来找的嘛,怎么就打印了?那么该怎么办呢 ?

那我们来调用下为数不多的脑细胞吧  -  函数传值不可以修改变量,传址可以修改变量,既然有思路了试试实现它

int find_num(int arr[3][3], int* px, int* py, int k)
{
	int x = 0;
	int y = *py - 1;

	while (x < *px && y >= 0)
	{
		if (arr[x][y] < k)
		{
			x++;
		}
		else if (arr[x][y] > k)
		{
			y--;
		}
		else
		{
			*px = x;
			*py = y;   //坐标带回去力!
			return 1;
		}
	}
	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 ret = find_num(arr, &x, &y, k);
	if (ret == 1)
	{
		printf("找到了\n");
		printf("下标是:%d %d\n", x, y);
	}
	else
	{
		printf("找不到了\n");
	}

	return 0;
}

&x和&y有两个作用:1.传入参数 2.带回值  (完美实现)

4.字符串左旋:

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

思路:
要实现左旋,要先拿个地址存放字符,把要左旋的字符放入这个地址里然后把后面的元素往前拿,就可以实现一个左旋,如果要实现两个及以上加个循环就可以了
代码实现:

void string_left_rotate(char* str, int k)
{
	int i = 0;
	int n = strlen(str);
	for (i = 0;i < k;i++)
	{
		//每次左旋转一个字符
		
		//1.把第一个字符拿出来
		char tmp = *str;
		//2.后面的n-1字符往前挪动
		int j = 0;
		for (j = 0;j < n - 1;j++)
		{
			*(str + j) = *(str + j + 1);
		}
		//3.tmp放在最后
		*(str + n - 1) = tmp;
	}
}

int main()
{
	char arr[10] = "ABCDEF";
	int k = 2;
	string_left_rotate(arr,k);
	printf("%s\n", arr);

	return 0;
}

so easy啦~

还有其他解法嘛?

思路:
可以把要旋转的字符当成一部分,把不要旋转的当一部分,把它们分别逆序一次,再整体逆序一次,即可完成
例子:
A B C D E F ->  B A F E D C -> C D E F A B
代码实现:

#include <stdio.h>
#include <string.h>
#include <assert.h>

void reverse(char* left, char* right)
{
	assert(left);
	assert(right);		  //养成断言的好习惯哦~
	while (left < right)
	{
		char tmp = *left; //1.把第一个元素的指针放到tmp里
		*left = *right;   //2.最后个元素放第一个元素的地址里
		*right = tmp;	  //3.第一个元素放最后个元素的地址里
		left++;
		right--;
	}
}

void string_left_rotate(char* str, int k)
{
	assert(str);
	int n = strlen(str);
	reverse(str, str + k - 1);		//左
	reverse(str + k, str + n - 1);  //右
	reverse(str, str + n - 1);      //整体
}

int main()
{
	char arr[10] = "ABCDEF";
	int k = 2;
	string_left_rotate(arr,k);
	printf("%s\n", arr);

	return 0;
}

5.字符串旋转结束
写一个函数,判断一个字符串是否位另外一个字符串旋转之后的字符串
例如:
给定s1 = AABCD和s2 = BCDAA,返回1
给定s1 = abcd和s2 = ABCD,放回0
代码实现:

int is_string_rotate(char* str1, char* str2)
{
	int i = 0;
	int n = strlen(str1);//5
	for (i = 0;i < n;i++)
	{
		char tmp = *str1;
		int j = 0;
		for (j = 0;j < n - 1;j++)
		{
			*(str1 + j) = *(str1 + j + 1);
		}
		*(str1 + n - 1) = tmp;

		if (strcmp(str1, str2) == 0)
		{
			return 1;
		}
	}
	return 0;
}
int main()
{
	char arr1[] = "AABCD";
	char arr2[] = "BCDAA";
	int ret = is_string_rotate(arr1, arr2);
	if (ret == 1)
	{
		printf("yes\n");
	}
	else
	{
		printf("no\n");
	}
	return 0;
}

那么还有其他实现方法吗?
思路:再造一个字符串AABCD AABCD ,会发现它包含了所有字符旋转的可能性,那么把BCDAA放进去找,如果找到了它就是旋转的结果

我们先来认识一个新的函数,strcat()和strncat();

例子:

int main()
{
	char arr1[20] = "hello ";
	char arr2[20] = "hello ";
	strcat(arr1,"bit");     //引用头文件<string.h>,后面加bit
	strncat(arr2, arr2, 5); //后面加arr,5个元素
	printf("%s\n", arr1);   //hello bit
	printf("%s\n", arr2);   //hello hello
	return 0;
}

代码实现:

int is_string_rotate(char* str1, char* str2)
{
	//长度不相等,肯定不是旋转得来的
	if (strlen(str1) != strlen(str2))
	{
		return 0;
	}

	//1.str1字符串的后边追加一个str1
	//AABCDAABCD
	int len = strlen(str1);
	strncat(str1,str1,len);        //字符串追加

	//2.判断str2是否为str1的子串
	char* ret = strstr(str1,str2); //判断一个字符串是不是另外一个字符串的子串
	//str1:AABCDAABCD
	//str2:  BCDAA
	//找到了返回一个地址,找不到返回一个空指针

	return ret != NULL;//简化结果,但是有个小的漏洞,比如BCD也是它的子串
					   //那么就在开头补充判断条件
					   
	//if (ret == NULL) //可以像上面那样简化
	//{
	//	return 0;
	//}
	//else
	//{
	//	return 1;
	//}

}
int main()
{
	char arr1[20] = "AABCD";
	char arr2[] = "BCDAA";
	int ret = is_string_rotate(arr1, arr2);
	if (ret == 1)
	{
		printf("yes\n");
	}
	else
	{
		printf("no\n");
	}
	return 0;
}

指针总结:
指针:          数组:          指针运算:
一级指针    一维数组    解引用
二级指针    二维数组    指针+-整数

整形指针    整形数组    指针-指针
字符指针    字符数组    指针的关系运算
..                 ..
数组指针    指针数组
函数指针
指针一定要学好,数据结构要用哦~!

如果喜欢我的博文可以点赞收藏关注,我将会为你带来更多优质文章!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值