一、指针进阶
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. }