C进阶习题(上)

简介: C进阶习题(上)

一、指针进阶

1.1 知识点

(1)指针的数据类型,声明的是指针实际指向内容的数据类型;free释放后,并不会自动置为NULL;野指针指向的是未分配或者已经释放的内存地址

(2)int类型的指针数组,就是一个数组,里面存放的是int*

(3)函数return返回值,不能返回两个(可以通过地址传址),可以一个,可以没有

(4)定义一个函数指针,指向的函数有两个int形参并且返回一个函数指针,返回的指针指向一个有一个int形参且返回int的函数  int (*(*F)(int, int))(int)

(5)声明一个指向含有10个元素的数组的指针,其中每个元素是一个函数指针,该函数的返回值是int,参数是int*,(int (*(*p)[10])(int *)  【4 5要求会写】

(6)一个地址是否能放到指针里面,要看指针指向内容的类型是否是该地址指向内容的类型

(7)函数的声明:int Add(int a, int b)  或者是 int Add(int, int);

(8) 做选择题,要注意是单选题还是多选题

(9)int arr[3][5]; int (*arr)[5] 指的是,一个指针指向的是二维数组第一行

1.2 实现一个函数,左旋字符串中的K个字符(旋转字符串)可以类比右旋)

方法一:

1. #include <stdio.h>
2. #include <string.h>
3. //思路:字符串的第一个元素,拿出来放在一个空间里面,再把字符串向前移一位,
4. //再把新的空间里面的元素放在字符串所在空间的最后一个位置
5. void left_move(char* str, int k)
6. {
7.  int i = 0;
8.  for (i = 0; i < k; i++)
9.  {
10.     //每次一个字符
11.     char tmp = *str;
12.     int len = 0;
13.     len = strlen(str);
14.     int j = 0;
15.     for (j = 0; j < len - 1; j++)
16.     {
17.       *(str + j) = *(str + j + 1);
18.     } 
19.     *(str + len - 1) = tmp;
20.   }
21. }
22. 
23. int main()
24. {
25.   char arr[] = "abcdef";//一般用数组存放字符串
26.   int k = 0;
27.   scanf("%d", &k);
28.   left_move(arr, k);
29.   printf("%s\n", arr);
30.   return 0;
31. }

方法二:

1. #include <stdio.h>
2. #include <string.h>
3. //思路:三步反转法,首先需要左移的字符进行逆序进行逆序,
4. //然后字符串不需要进行左移的字符进行逆转,最后整个字符串的元素进行逆序
5. //逆序函数
6. void reverse(char* left, char* right)
7. //学习完指针之后,用指针,不需要用数组下标
8. {
9.  while (left < right)
10.   {
11.     char tmp = *left;
12.     *left = *right;
13.     *right = tmp;
14.     left++;
15.     right--;
16.   }
17. }
18. 
19. //左移函数
20. void left_move(char* str, int k)
21. {
22.   int len = strlen(str);
23.   k = k % len;//这个点要注意,容易忽略
24.   reverse(str, str + k - 1);
25.   reverse(str + k, str + len - 1);
26.   reverse(str, str + len - 1);
27. }
28. 
29. int main()
30. {
31.   char arr[] = "abcdef";//一般用数组存放字符串
32.   int k = 0;
33.   scanf("%d", &k);
34.   left_move(arr, k);
35.   printf("%s\n", arr);
36.   return 0;
37. }

1.3 有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在,时间复杂度小于O(N)[说明,不可以遍历整个数组]。(杨氏矩阵)

代码一:(这种写法不是特别的好)

1. #include <stdio.h>
2. //思路:因为每一行每一列都是递增的,所以需要查找的数字,
3. //只需要和每一行的最后一个元素进行比较(不能和第一个元素进行比较)【可以从右上角以及左下角开始】,如果大于
4. //就可以对下一行进行比较。小于后,找到相应的行,
5. //然后对该行的元素进行比较,从后向前比较,如果该行遍历完之后还是没有,
6. //就说明没有这个数字
7. void find_int_arr(int arr[3][3], int r, int c, int k)
8. {
9.  int x = 0;
10.   int y = c - 1;
11.   while (x <= r - 1 && y >= 0)
12.   {
13.     if (arr[x][y] < k)
14.     {
15.       x++;
16.     }
17.     else if (arr[x][y] > k)
18.     {
19.       y--;
20.     }
21.     else
22.     {
23.       printf("找到了,下标是:x = %d y = %d\n", x, y);
24.       return;
25.     }
26.   }
27.   printf("找不到\n");
28. }
29. 
30. 
31. int main()
32. {
33.   int arr[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
34.   int k = 0;
35.   scanf("%d", &k);
36.   find_int_arr(arr, 3, 3, k);
37.   return 0;
38. }

代码2:(优化后的代码)

1. #include <stdio.h>
2. //区别:函数返回下标的值,以及找不到的内容,
3. //通过地址传址
4. void find_int_arr(int arr[3][3], int* px, int* py, int k)
5. {
6.  int x = 0;
7.  int y = *py -1; 
8.  while (x <= *px - 1 && y >= 0)
9.  {
10.     if (arr[x][y] < k)
11.     {
12.       x++;
13.     }
14.     else if (arr[x][y] > k)
15.     {
16.       y--;
17.     }
18.     else
19.     {
20.       *px = x;
21.       *py = y;
22.       return;
23.     }
24.   }
25.   *px = -1;
26.   *py = -1;
27. }
28. 
29. int main()
30. {
31.   int arr[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
32.   int x = 3;
33.   int y = 3;
34.   int k = 0;
35.   scanf("%d", &k);
36.   //参数是返回型参数
37.   find_int_arr(arr, &x, &y, k);
38.   if (x == -1 && y == -1)
39.   {
40.     printf("找不到\n");
41.   }
42.   else
43.   {
44.     printf("找到了,下标是:%d %d", x, y);
45.   }
46.   return 0;
47. }

1.4  写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。是的话,返回1,否返回0

方法一:

1. //判断是一个字符串的旋转字符
2. //思路:旋转判断旋转判断
3. #include <stdio.h>
4. #include <string.h>
5. void reverse(char* left, char* right)
6. {
7.  while (left < right)
8.  {
9.    char tmp = *left;
10.     *left = *right;
11.     *right = tmp;
12.     left++;
13.     right--;
14.   }
15. }
16. //左移函数
17. void left_move(char* str, int k)
18. {
19.   int len = strlen(str);
20.   k = k % len;//这个点要注意,容易忽略
21.   reverse(str, str + k - 1);
22.   reverse(str + k, str + len - 1);
23.   reverse(str, str + len - 1);
24. }
25. int is_left_move(char* arr1, char* arr2)
26. {
27.   int len = strlen(arr1);
28.   int i = 0;
29.   for (i = 0; i < len; i++)
30.   {
31.     left_move(arr1, 1);
32.     if (strcmp(arr1, arr2) == 0)
33.       return 1;
34.   }
35.   return 0;
36. }
37. 
38. int main()
39. {
40.   char arr1[] = "AABCD";
41.   char arr2[] = "BCDAA";
42.   int ret = is_left_move(arr1, arr2);
43.   printf("%d\n", ret);
44.   return 0;
45. }

方法二:

1. // 判断是一个字符串的旋转字符
2. //思路:字符串追加本身,再判断是否包含里面,包含就是旋转字符
3. #include <stdio.h>
4. #include <string.h>
5. 
6. int is_left_move(char* arr1, char* arr2)
7. {
8.  int len1 = strlen(arr1);
9.  int len2 = strlen(arr2);
10.   if (len1 != len2)
11.     return 0;
12.   strncat(arr1, arr1, len1);
13.   if (strstr(arr1, arr2))
14.     return 1;
15.   else
16.     return 0; 
17. }
18. 
19. int main()
20. {
21.   char arr1[20] = "AABCD";
22.   char arr2[] = "BCDAA";
23.   int ret = is_left_move(arr1, arr2);
24.   printf("%d\n", ret);
25.   return 0;
26. }

动态内存分配

2.1 知识点

(1)枚举,打印出来,依次加一,相较于上一个(除了,定义时候就赋值的)

(2)define定义的标识符常量,是替换内容。需要带进去,而不是计算完再代入(易错点)

2.2代码结果

1. int main()
2. {
3.   unsigned char puc[4];
4. struct tagPIM
5.   {
6.     unsigned char ucPim1;
7.     unsigned char ucData0 : 1;
8.     unsigned char ucData1 : 2;
9.     unsigned char ucData2 : 3;
10.   }*pstPimData;
11.   pstPimData = (struct tagPIM*)puc;
12.   memset(puc,0,4);
13.   pstPimData->ucPim1 = 2; 
14.   pstPimData->ucData0 = 3;
15.   pstPimData->ucData1 = 4;
16.   pstPimData->ucData2 = 5;
17.   printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);
18. return 0;
19. }

结果为:02 29 00 00

知识点:%x指的是打印16进制;%02x指的是,打印两位

2.3  

1. #include<stdio.h>
2. int main()
3. {
4.   union
5.   {
6. short k;
7. char i[2];
8.   }*s, a;
9.   s = &a;
10.   s->i[0] = 0x39;
11.   s->i[1] = 0x38;
12.   printf("%x\n", a.k);
13. return 0;
14. }

打印结果:3839

2.4 BC100-有序序列合并

输入两个升序排列的序列,将两个序列合并为一个有序序列并输出。输入描述:输入包含三行,第一行包含两个正整数n, m,用空格分隔。n表示第二行第一个升序序列中数字的个数,m表示第三行第二个升序序列中数字的个数。第二行包含n个整数,用空格分隔。第三行包含m个整数,用空格分隔。输出描述:输出为一行,输出长度为n+m的升序序列,即长度为n的升序序列和长度为m的升序序列中的元素重新进行升序序列排列合并。

1. #include <stdio.h>
2. int main()
3. {
4.  int n = 0;
5.  int m = 0;
6. //输入  
7.  scanf("%d %d", &n, &m);
8.  int arr1[n];//在C99标准就可以,牛客网支持
9.  int arr2[m];
10. //输入两个升序的序列
11. int i = 0;
12. for (i = 0; i < n; i++)
13.     {
14.         scanf("%d ", &arr1[i]);
15.     }
16. for (i = 0; i < m; i++)
17.     {
18.         scanf("%d ", &arr2[i]);
19.     }
20. //输出序列
21. int j = 0;
22.     i = 0;
23. while ((i < n) && (j < m))
24.     {
25. if (arr1[i] < arr2[j])
26.         {
27.             printf("%d ", arr1[i]);
28.             i++;
29.         }
30. else
31.         {
32.             printf("%d ", arr2[j]);
33.             j++;
34.         }
35.     }
36. if (i == n)
37.     {
38. for (; j < m; j++)
39.         {
40.             printf("%d ", arr2[j]);
41.         }
42.     }
43. else
44.     {
45. for (; i < n; i++)
46.         {
47.             printf("%d ", arr1[i]);
48.         }
49.     }
50. 
51.   return 0;
52. }


相关文章
|
存储 JSON 关系型数据库
mysql中find_in_set()函数用法详解及增强函数
总结而言,`FIND_IN_SET()`是MySQL中处理由逗号分隔的字符串列表的一种便捷方法,尤其适用于列表相对较短且不经常更改的场景。然而,对于更为复杂的需要高性能和可扩展性的数据库设计,它可能不是最优选择,应考虑使用更加正规化的数据库结构。
1759 2
mysql中find_in_set()函数用法详解及增强函数
|
XML 前端开发 Java
Spring Boot的Web开发之Thymeleaf模板引擎的解析及使用(Thymeleaf的基础语法以及常用属性)
Spring Boot的Web开发之Thymeleaf模板引擎的解析及使用(Thymeleaf的基础语法以及常用属性)
413 0
|
API 数据库 Android开发
构建高效安卓应用:Kotlin与协程的完美融合
【2月更文挑战第20天】在移动开发领域,性能优化和资源管理始终是开发者关注的焦点。随着Kotlin语言在Android平台的普及,协程作为其核心特性之一,提供了一种全新的异步编程范式。本文将深入探讨如何通过Kotlin协程提升安卓应用的性能,减少内存消耗,并实现流畅的用户体验。我们将分析协程的原理,展示其在实际应用中的效能,并提供实践指南,帮助开发者掌握这一强有力的工具。
101 0
|
机器学习/深度学习 数据挖掘 计算机视觉
超越MobileNet V3 | 详解SkipNet+Bias Loss=轻量化模型新的里程碑(二)
超越MobileNet V3 | 详解SkipNet+Bias Loss=轻量化模型新的里程碑(二)
357 0
|
SQL 缓存 监控
聊聊接口性能优化的11个小技巧
聊聊接口性能优化的11个小技巧
聊聊接口性能优化的11个小技巧
|
存储 C语言
C语言进阶之通讯录的实现(静态版和动态版)以及动态内存管理(上)
开头我们先断言,防止传NULL指针,第二步初始化长度为0,最后将结构体数组中的元素均初始化为0即可。
|
iOS开发 C++
【C++知识点】文件操作(二)
【C++知识点】文件操作(二)
160 0
|
JavaScript
js基础笔记学习9-常量
js基础笔记学习9-常量
88 0
js基础笔记学习9-常量
|
机器学习/深度学习 自然语言处理
nlp相关2
nlp相关
122 0
|
前端开发
前端工作小结76-整理订单的重置逻辑
前端工作小结76-整理订单的重置逻辑
185 0
前端工作小结76-整理订单的重置逻辑