总结一下C语言采坑之路

string.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. /* 将字符串src_拼接到dst_后,将回拼接的串地址 */
  4. char *strcat(char *dst_, const char *src_)
  5. {
  6. char *str = dst_;
  7. while (*str++);
  8. --str; // 别看错了,--str是独立的一句,并不是while的循环体
  9. while (*src_)
  10. {
  11. // 内联汇编和下面C语言代码等价
  12. asm volatile("movl %0,%%ebx;/* 将src_的内存地址传送到基址寄存器ebx */ \
  13. movb (%%ebx),%%al;/* 从基址寄存器ebx为基址寻址,得到src_内存地址处的值,传送到8位通用寄存器al */ \
  14. movl %1,%%ebx;/* 将str的内存地址传送到基址寄存器ebx */ \
  15. movb %%al,(%%ebx); /* 将8位通用寄存器al存储的值,传送到以基址寄存器ebx为基址寻址,得到str的内存地址处 */"
  16. :
  17. : "m"(src_), "m"(str)
  18. : "memory", "al", "ebx");
  19. // 与下面代码等价
  20. // char temp= *src_;
  21. // *str = temp; // 汇编寻址(*str)传送
  22. str++;
  23. src_++;
  24. }
  25. return dst_;
  26. }
  27. int main(int argc, char const *argv[])
  28. {
  29. /* code */
  30. // 正确用法
  31. char a[] = "123";
  32. char b[] = "456";
  33. char *c[] = {b}; // 指针数组
  34. printf("c:%s\n", *c);
  35. // 错误用法
  36. // char *a = "123";
  37. // char *b = "456";
  38. printf("a:%p\n", a); // 字符串与数组本身就是指针(头指针)
  39. printf("b:%p\n", b);
  40. strcat(a, b);
  41. printf("%s\n", a);
  42. system("pause");
  43. return 0;
  44. }

bitmap_1.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <string.h>
  5. //定义每个Byte中有8个Bit位
  6. #include <memory.h>
  7. #define BYTESIZE 8
  8. void SetBit(char *p, int posi)
  9. {
  10. p = p + (posi / BYTESIZE);
  11. *p = *p | (0x01 << (posi % BYTESIZE)); //将该Bit位赋值1,或操作会保留,位为1的二进制位
  12. return;
  13. }
  14. void BitMapSortDemo()
  15. {
  16. //为了简单起见,我们不考虑负数
  17. int num[] = {3, 5, 2, 10, 6, 12, 8, 14, 9};
  18. //BufferLen这个值是根据待排序的数据中最大值确定的
  19. //待排序中的最大值是14,因此只需要2个Bytes(16个Bit)
  20. //就可以了。
  21. const int BufferLen = 2;
  22. char p[BufferLen];
  23. char *pBuffer = p;
  24. //要将所有的Bit位置为0,否则结果不可预知。
  25. memset(pBuffer, 0, BufferLen);
  26. for (int i = 0; i < 9; i++)
  27. {
  28. //首先将相应Bit位上置为1
  29. SetBit(pBuffer, num[i]);
  30. }
  31. //输出排序结果
  32. for (int i = 0; i < BufferLen; i++) //每次处理一个字节(Byte)
  33. {
  34. for (int j = 0; j < BYTESIZE; j++) //处理该字节中的每个Bit位
  35. {
  36. //判断该位上是否是1,进行输出,这里的判断比较笨。
  37. //首先得到该第j位的掩码(0x01<<j),将内存区中的
  38. //位和此掩码作与操作。最后判断掩码是否和处理后的
  39. //结果相同
  40. printf("%c\n", *pBuffer);
  41. printf("%d\n", (*pBuffer & (0x01 << j)));
  42. // printf("\n");
  43. printf("%d\n", (0x01 << j));
  44. printf("\n");
  45. if ((*pBuffer & (0x01 << j)) == (0x01 << j))
  46. {
  47. printf("%d ", i * BYTESIZE + j);
  48. }
  49. }
  50. pBuffer++;
  51. }
  52. }
  53. int main(int argc, char const *argv[])
  54. {
  55. BitMapSortDemo();
  56. system("pause");
  57. return 0;
  58. }

bitmap_2.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <string.h>
  5. //定义每个Byte中有8个Bit位
  6. #include <memory.h>
  7. #define BYTESIZE 8
  8. #ifndef _LIB_STDINT_H
  9. #define _LIB_STDINT_H
  10. typedef signed char int8_t;
  11. typedef signed short int int16_t;
  12. typedef signed int int32_t;
  13. typedef signed long long int int64_t;
  14. typedef unsigned char uint8_t;
  15. typedef unsigned short int uint16_t;
  16. typedef unsigned int uint32_t;
  17. typedef unsigned long long int uint64_t;
  18. #endif
  19. /*
  20. https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/06.07.md
  21. */
  22. #define BITMAP_MASK 1 // 宏BITMAP_MASK其值为1,用来在位图中逐位判断,主要就是通过按位与‘&’来判断相应位是否为1。
  23. // struct bitmap中只定义了两个成员:位图的指针bits和位图的字节长度btmp_bytes_len。
  24. struct bitmap
  25. {
  26. uint32_t btmp_bytes_len;
  27. /* 在遍历位图时,整体上以字节为单位,细节上是以位为单位,所以此处位图的指针必须是单字节 */
  28. uint8_t *bits; // *指针就是内存地址,这里声明的意思是指针的类型是uint8_t,仍然是内存地址。不同指针类型,在地址处取值时(*指针)的方法和长度不同而已
  29. };
  30. void SetBit(char *p, int posi);
  31. bool bitmap_scan_test(struct bitmap *btmp, uint32_t bit_idx);
  32. void printbit(char *pBuffer);
  33. void BitMapSortDemo(void);
  34. void BitMapSortDemo1(void);
  35. /* 判断bit_idx位是否为1,若为1则返回true,否则返回false */
  36. // bitmap_scan_test函数接受两个参数,分别是位图指针btmp和位索引bit_idx。其功能是判断位图btmp中的第bit_idx位是否为1,若为1,则返回true,否则返回false。
  37. // 如果bit_idx为10的话,byte_idx为1,bit_odd为2,字节索引1中的位1
  38. bool bitmap_scan_test(struct bitmap *btmp, uint32_t bit_idx)
  39. {
  40. uint32_t byte_idx = bit_idx / 8; // 向下取整用于索引数组下标
  41. uint32_t bit_odd = bit_idx % 8; // 取余用于索引数组内的位
  42. uint8_t *bb = btmp->bits;
  43. printf("%c\n", *bb);
  44. uint8_t cc = btmp->bits[byte_idx];
  45. printf("%c\n", cc);
  46. int adds = btmp->bits[byte_idx];
  47. char *dds = (char *)&adds; // 先转成int*,然后转换为char* 指针也有类型,主要是为了从内存中取值用做依据
  48. printbit(dds);
  49. uint32_t left = btmp->bits[byte_idx];
  50. uint32_t right = (BITMAP_MASK << (8 - bit_odd - 1));
  51. printbit((char *)&left);
  52. printbit((char *)&right);
  53. printf("left: %d,right: %d\n", left, right);
  54. return (left & right);
  55. }
  56. // 打印一字节二进制
  57. void printbit(char *pBuffer)
  58. {
  59. int res = *pBuffer;
  60. int count = 7;
  61. printf("byte:");
  62. for (int i = 0; i < 8; i++)
  63. {
  64. printf("%d", (res & (0x01 << count)) == 0 ? 0 : 1);
  65. count--;
  66. }
  67. printf("\n");
  68. }
  69. void SetBit(char *p, int posi)
  70. {
  71. p = p + (posi / BYTESIZE);
  72. *p = *p | (0x01 << (posi % BYTESIZE)); //将该Bit位赋值1,或操作会保留,位为1的二进制位
  73. return;
  74. }
  75. void BitMapSortDemo(void)
  76. {
  77. //为了简单起见,我们不考虑负数
  78. int num[] = {4, 7, 2, 5, 3};
  79. //BufferLen这个值是根据待排序的数据中最大值确定的
  80. //待排序中的最大值是14,因此只需要2个Bytes(16个Bit)
  81. //就可以了。
  82. const int BufferLen = 1;
  83. char p[BufferLen];
  84. char *pBuffer = p;
  85. //要将所有的Bit位置为0,否则结果不可预知。
  86. memset(pBuffer, 0, BufferLen);
  87. for (int i = 0; i < 5; i++)
  88. {
  89. //首先将相应Bit位上置为1
  90. SetBit(pBuffer, num[i]);
  91. }
  92. uint8_t *u = (uint8_t *)pBuffer;
  93. struct bitmap map = {
  94. 1,
  95. u};
  96. bool r = bitmap_scan_test(&map, 6);
  97. printf("%d\n", r);
  98. // 0b10111100
  99. // 0b00000001
  100. //输出排序结果
  101. for (int i = 0; i < BufferLen; i++) //每次处理一个字节(Byte)
  102. {
  103. printbit(pBuffer);
  104. for (int j = 0; j < BYTESIZE; j++) //处理该字节中的每个Bit位
  105. {
  106. //判断该位上是否是1,进行输出,这里的判断比较笨。
  107. //首先得到该第j位的掩码(0x01<<j),将内存区中的
  108. //位和此掩码作与操作。最后判断掩码是否和处理后的
  109. //结果相同
  110. printf("*pBuffer:%c\n", *pBuffer);
  111. printf("*pBuffer & (0x01 << j):%d\n", (*pBuffer & (0x01 << j)));
  112. // printf("\n");
  113. printf("(0x01 << j):%d\n", (0x01 << j));
  114. printf("\n");
  115. // 0b00000001 & 0b00000001 == 0b00000001
  116. // *pBuffer 0x01 << j 0x01 << j j
  117. // 0b10111100 & 0b00000001 == 0b00000001 0
  118. // 0b10111100 & 0b00000010 == 0b00000010 1
  119. // 0b10111100 & 0b00000100 == 0b00000100 2
  120. // 0b10111100 & 0b00001000 == 0b00001000 3
  121. if ((*pBuffer & (0x01 << j)) == (0x01 << j))
  122. {
  123. printf("%d ", i * BYTESIZE + j);
  124. }
  125. }
  126. pBuffer++;
  127. }
  128. }
  129. void BitMapSortDemo1(void)
  130. {
  131. //为了简单起见,我们不考虑负数
  132. int num[] = {3, 5, 2, 10, 6, 12, 8, 14, 9};
  133. int len = sizeof(num) / sizeof(num[0]);
  134. printf("%d", len);
  135. //BufferLen这个值是根据待排序的数据中最大值确定的
  136. //待排序中的最大值是14,因此只需要2个Bytes(16个Bit)
  137. //就可以了。
  138. const int BufferLen = 2;
  139. char p[BufferLen];
  140. char *pBuffer = p;
  141. //要将所有的Bit位置为0,否则结果不可预知。
  142. memset(pBuffer, 0, BufferLen);
  143. for (int i = 0; i < len; i++)
  144. {
  145. //首先将相应Bit位上置为1
  146. SetBit(pBuffer, num[i]);
  147. }
  148. // uint8_t *u = (uint8_t *)pBuffer; // 指针也有类型,主要是为了从内存中取值用做依据
  149. uint8_t *u = (uint8_t *)pBuffer;
  150. printf("%p\n", u);
  151. printf("%c\n", *u);
  152. struct bitmap map = {
  153. 2,
  154. u};
  155. bool r = bitmap_scan_test(&map, 11);
  156. printf("%d\n", r);
  157. // 0b10111100
  158. // 0b00000001
  159. //输出排序结果
  160. for (int i = 0; i < BufferLen; i++) //每次处理一个字节(Byte)
  161. {
  162. printbit(pBuffer);
  163. for (int j = 0; j < BYTESIZE; j++) //处理该字节中的每个Bit位
  164. {
  165. //判断该位上是否是1,进行输出,这里的判断比较笨。
  166. //首先得到该第j位的掩码(0x01<<j),将内存区中的
  167. //位和此掩码作与操作。最后判断掩码是否和处理后的
  168. //结果相同
  169. printf("*pBuffer:%c\n", *pBuffer);
  170. printf("*pBuffer & (0x01 << j):%d\n", (*pBuffer & (0x01 << j)));
  171. // printf("\n");
  172. printf("(0x01 << j):%d\n", (0x01 << j));
  173. printf("\n");
  174. // 0b00000001 & 0b00000001 == 0b00000001
  175. // *pBuffer 0x01 << j 0x01 << j j
  176. // 0b10111100 & 0b00000001 == 0b00000001 0
  177. // 0b10111100 & 0b00000010 == 0b00000010 1
  178. // 0b10111100 & 0b00000100 == 0b00000100 2
  179. // 0b10111100 & 0b00001000 == 0b00001000 3
  180. if ((*pBuffer & (0x01 << j)) == (0x01 << j))
  181. {
  182. printf("---%d---\n", i * BYTESIZE + j);
  183. }
  184. }
  185. pBuffer++;
  186. }
  187. }
  188. int main(int argc, char const *argv[])
  189. {
  190. (void) argc;
  191. (void) argv;
  192. // BitMapSortDemo1();
  193. BitMapSortDemo();
  194. system("pause");
  195. return 0;
  196. }

struct.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <memory.h>
  4. struct student generate(char name[], int age, int gender);
  5. void foo(void);
  6. struct student
  7. {
  8. // 我指定的是32位,而非64位
  9. char *name; // name (指针4字节) 存储的是字符串指针也就是字符串的内存地址
  10. unsigned int age; // age (unsigned int 4字节)
  11. unsigned int gender; // gender (unsigned int 4字节)
  12. }; /*无论如何赋值结构体sizeof都是12字节*/
  13. struct student generate(char name[], int age, int gender)
  14. {
  15. char *ming = name;
  16. struct student xiaoming = {
  17. ming,
  18. age,
  19. gender};
  20. printf("%s %d\n", name, sizeof(xiaoming));
  21. printf("%d\n", *(unsigned int *)((unsigned int)&xiaoming + 4)); // 骚操作,拆解
  22. // 目的是取结构体的第二个结构变量
  23. // 1. &xiaoming 取结构体的指针即内存地址,起始内存地址
  24. // 2. (unsigned int)&xiaoming 类型转换,方便加步长来寻址,如同汇编
  25. // 3. (unsigned int)&xiaoming + 4 加上步长来寻址,步长位字节。这里是加上4字节,因为第一个结构体变量长度就是4字节,加上这个长度步长,跳过第一个结构体变量。
  26. // 4. (unsigned int *)((unsigned int)&xiaoming + 4)) 得到第二个结构体变量内存地址后,类型转换为(unsigned int *)的指针
  27. // 5. *(unsigned int *)((unsigned int)&xiaoming + 4)) 最后取指针地址,得到第二个结构体变量
  28. return xiaoming;
  29. }
  30. void foo(void)
  31. {
  32. // char n[] = "哈哈";
  33. generate("xiaoming", 16, 1);
  34. generate("xiaoli", 18, 1);
  35. generate("hahahahahahhahahahahahahahahahahahahahahhahaha", 20, 1);
  36. generate("hello my name is xiaoliu", 120, 1);
  37. }
  38. int main(int argc, char const *argv[])
  39. {
  40. (void)argc;
  41. (void)argv;
  42. printf("struct\n");
  43. foo();
  44. system("pause");
  45. return 0;
  46. }

memory.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <memory.h>
  4. #define PSGE_SIZE 4096
  5. struct student
  6. {
  7. char *name; // name
  8. unsigned int age; // age
  9. unsigned int gender; // gender
  10. };
  11. void foo(void);
  12. void foo(void)
  13. {
  14. void *p = malloc(PSGE_SIZE);
  15. printf("0x%x\n", PSGE_SIZE);
  16. memset(p, 0, PSGE_SIZE);
  17. for (int i = 0; i < 13; i++)
  18. {
  19. printf("0x%x\n", *(int *)((unsigned int)p + i));
  20. }
  21. struct student *s = (struct student *)p;
  22. printf("%x\n", sizeof(*s));
  23. }
  24. int main(int argc, char const *argv[])
  25. {
  26. (void)argc;
  27. (void)argv;
  28. printf("struct\n");
  29. foo();
  30. system("pause");
  31. return 0;
  32. }