总结一下C语言采坑之路
string.c
#include <stdio.h>#include <stdlib.h>/* 将字符串src_拼接到dst_后,将回拼接的串地址 */char *strcat(char *dst_, const char *src_){ char *str = dst_; while (*str++); --str; // 别看错了,--str是独立的一句,并不是while的循环体 while (*src_) { // 内联汇编和下面C语言代码等价 asm volatile("movl %0,%%ebx;/* 将src_的内存地址传送到基址寄存器ebx */ \ movb (%%ebx),%%al;/* 从基址寄存器ebx为基址寻址,得到src_内存地址处的值,传送到8位通用寄存器al */ \ movl %1,%%ebx;/* 将str的内存地址传送到基址寄存器ebx */ \ movb %%al,(%%ebx); /* 将8位通用寄存器al存储的值,传送到以基址寄存器ebx为基址寻址,得到str的内存地址处 */" : : "m"(src_), "m"(str) : "memory", "al", "ebx"); // 与下面代码等价 // char temp= *src_; // *str = temp; // 汇编寻址(*str)传送 str++; src_++; } return dst_;}int main(int argc, char const *argv[]){ /* code */ // 正确用法 char a[] = "123"; char b[] = "456"; char *c[] = {b}; // 指针数组 printf("c:%s\n", *c); // 错误用法 // char *a = "123"; // char *b = "456"; printf("a:%p\n", a); // 字符串与数组本身就是指针(头指针) printf("b:%p\n", b); strcat(a, b); printf("%s\n", a); system("pause"); return 0;}
bitmap_1.c
#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <string.h>//定义每个Byte中有8个Bit位#include <memory.h>#define BYTESIZE 8void SetBit(char *p, int posi){ p = p + (posi / BYTESIZE); *p = *p | (0x01 << (posi % BYTESIZE)); //将该Bit位赋值1,或操作会保留,位为1的二进制位 return;}void BitMapSortDemo(){ //为了简单起见,我们不考虑负数 int num[] = {3, 5, 2, 10, 6, 12, 8, 14, 9}; //BufferLen这个值是根据待排序的数据中最大值确定的 //待排序中的最大值是14,因此只需要2个Bytes(16个Bit) //就可以了。 const int BufferLen = 2; char p[BufferLen]; char *pBuffer = p; //要将所有的Bit位置为0,否则结果不可预知。 memset(pBuffer, 0, BufferLen); for (int i = 0; i < 9; i++) { //首先将相应Bit位上置为1 SetBit(pBuffer, num[i]); } //输出排序结果 for (int i = 0; i < BufferLen; i++) //每次处理一个字节(Byte) { for (int j = 0; j < BYTESIZE; j++) //处理该字节中的每个Bit位 { //判断该位上是否是1,进行输出,这里的判断比较笨。 //首先得到该第j位的掩码(0x01<<j),将内存区中的 //位和此掩码作与操作。最后判断掩码是否和处理后的 //结果相同 printf("%c\n", *pBuffer); printf("%d\n", (*pBuffer & (0x01 << j))); // printf("\n"); printf("%d\n", (0x01 << j)); printf("\n"); if ((*pBuffer & (0x01 << j)) == (0x01 << j)) { printf("%d ", i * BYTESIZE + j); } } pBuffer++; }}int main(int argc, char const *argv[]){ BitMapSortDemo(); system("pause"); return 0;}
bitmap_2.c
#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <string.h>//定义每个Byte中有8个Bit位#include <memory.h>#define BYTESIZE 8#ifndef _LIB_STDINT_H#define _LIB_STDINT_Htypedef signed char int8_t;typedef signed short int int16_t;typedef signed int int32_t;typedef signed long long int int64_t;typedef unsigned char uint8_t;typedef unsigned short int uint16_t;typedef unsigned int uint32_t;typedef unsigned long long int uint64_t;#endif/*https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/06.07.md*/#define BITMAP_MASK 1 // 宏BITMAP_MASK其值为1,用来在位图中逐位判断,主要就是通过按位与‘&’来判断相应位是否为1。// struct bitmap中只定义了两个成员:位图的指针bits和位图的字节长度btmp_bytes_len。struct bitmap{ uint32_t btmp_bytes_len; /* 在遍历位图时,整体上以字节为单位,细节上是以位为单位,所以此处位图的指针必须是单字节 */ uint8_t *bits; // *指针就是内存地址,这里声明的意思是指针的类型是uint8_t,仍然是内存地址。不同指针类型,在地址处取值时(*指针)的方法和长度不同而已};void SetBit(char *p, int posi);bool bitmap_scan_test(struct bitmap *btmp, uint32_t bit_idx);void printbit(char *pBuffer);void BitMapSortDemo(void);void BitMapSortDemo1(void);/* 判断bit_idx位是否为1,若为1则返回true,否则返回false */// bitmap_scan_test函数接受两个参数,分别是位图指针btmp和位索引bit_idx。其功能是判断位图btmp中的第bit_idx位是否为1,若为1,则返回true,否则返回false。// 如果bit_idx为10的话,byte_idx为1,bit_odd为2,字节索引1中的位1bool bitmap_scan_test(struct bitmap *btmp, uint32_t bit_idx){ uint32_t byte_idx = bit_idx / 8; // 向下取整用于索引数组下标 uint32_t bit_odd = bit_idx % 8; // 取余用于索引数组内的位 uint8_t *bb = btmp->bits; printf("%c\n", *bb); uint8_t cc = btmp->bits[byte_idx]; printf("%c\n", cc); int adds = btmp->bits[byte_idx]; char *dds = (char *)&adds; // 先转成int*,然后转换为char* 指针也有类型,主要是为了从内存中取值用做依据 printbit(dds); uint32_t left = btmp->bits[byte_idx]; uint32_t right = (BITMAP_MASK << (8 - bit_odd - 1)); printbit((char *)&left); printbit((char *)&right); printf("left: %d,right: %d\n", left, right); return (left & right);}// 打印一字节二进制void printbit(char *pBuffer){ int res = *pBuffer; int count = 7; printf("byte:"); for (int i = 0; i < 8; i++) { printf("%d", (res & (0x01 << count)) == 0 ? 0 : 1); count--; } printf("\n");}void SetBit(char *p, int posi){ p = p + (posi / BYTESIZE); *p = *p | (0x01 << (posi % BYTESIZE)); //将该Bit位赋值1,或操作会保留,位为1的二进制位 return;}void BitMapSortDemo(void){ //为了简单起见,我们不考虑负数 int num[] = {4, 7, 2, 5, 3}; //BufferLen这个值是根据待排序的数据中最大值确定的 //待排序中的最大值是14,因此只需要2个Bytes(16个Bit) //就可以了。 const int BufferLen = 1; char p[BufferLen]; char *pBuffer = p; //要将所有的Bit位置为0,否则结果不可预知。 memset(pBuffer, 0, BufferLen); for (int i = 0; i < 5; i++) { //首先将相应Bit位上置为1 SetBit(pBuffer, num[i]); } uint8_t *u = (uint8_t *)pBuffer; struct bitmap map = { 1, u}; bool r = bitmap_scan_test(&map, 6); printf("%d\n", r); // 0b10111100 // 0b00000001 //输出排序结果 for (int i = 0; i < BufferLen; i++) //每次处理一个字节(Byte) { printbit(pBuffer); for (int j = 0; j < BYTESIZE; j++) //处理该字节中的每个Bit位 { //判断该位上是否是1,进行输出,这里的判断比较笨。 //首先得到该第j位的掩码(0x01<<j),将内存区中的 //位和此掩码作与操作。最后判断掩码是否和处理后的 //结果相同 printf("*pBuffer:%c\n", *pBuffer); printf("*pBuffer & (0x01 << j):%d\n", (*pBuffer & (0x01 << j))); // printf("\n"); printf("(0x01 << j):%d\n", (0x01 << j)); printf("\n"); // 0b00000001 & 0b00000001 == 0b00000001 // *pBuffer 0x01 << j 0x01 << j j // 0b10111100 & 0b00000001 == 0b00000001 0 // 0b10111100 & 0b00000010 == 0b00000010 1 // 0b10111100 & 0b00000100 == 0b00000100 2 // 0b10111100 & 0b00001000 == 0b00001000 3 if ((*pBuffer & (0x01 << j)) == (0x01 << j)) { printf("%d ", i * BYTESIZE + j); } } pBuffer++; }}void BitMapSortDemo1(void){ //为了简单起见,我们不考虑负数 int num[] = {3, 5, 2, 10, 6, 12, 8, 14, 9}; int len = sizeof(num) / sizeof(num[0]); printf("%d", len); //BufferLen这个值是根据待排序的数据中最大值确定的 //待排序中的最大值是14,因此只需要2个Bytes(16个Bit) //就可以了。 const int BufferLen = 2; char p[BufferLen]; char *pBuffer = p; //要将所有的Bit位置为0,否则结果不可预知。 memset(pBuffer, 0, BufferLen); for (int i = 0; i < len; i++) { //首先将相应Bit位上置为1 SetBit(pBuffer, num[i]); } // uint8_t *u = (uint8_t *)pBuffer; // 指针也有类型,主要是为了从内存中取值用做依据 uint8_t *u = (uint8_t *)pBuffer; printf("%p\n", u); printf("%c\n", *u); struct bitmap map = { 2, u}; bool r = bitmap_scan_test(&map, 11); printf("%d\n", r); // 0b10111100 // 0b00000001 //输出排序结果 for (int i = 0; i < BufferLen; i++) //每次处理一个字节(Byte) { printbit(pBuffer); for (int j = 0; j < BYTESIZE; j++) //处理该字节中的每个Bit位 { //判断该位上是否是1,进行输出,这里的判断比较笨。 //首先得到该第j位的掩码(0x01<<j),将内存区中的 //位和此掩码作与操作。最后判断掩码是否和处理后的 //结果相同 printf("*pBuffer:%c\n", *pBuffer); printf("*pBuffer & (0x01 << j):%d\n", (*pBuffer & (0x01 << j))); // printf("\n"); printf("(0x01 << j):%d\n", (0x01 << j)); printf("\n"); // 0b00000001 & 0b00000001 == 0b00000001 // *pBuffer 0x01 << j 0x01 << j j // 0b10111100 & 0b00000001 == 0b00000001 0 // 0b10111100 & 0b00000010 == 0b00000010 1 // 0b10111100 & 0b00000100 == 0b00000100 2 // 0b10111100 & 0b00001000 == 0b00001000 3 if ((*pBuffer & (0x01 << j)) == (0x01 << j)) { printf("---%d---\n", i * BYTESIZE + j); } } pBuffer++; }}int main(int argc, char const *argv[]){ (void) argc; (void) argv; // BitMapSortDemo1(); BitMapSortDemo(); system("pause"); return 0;}
struct.c
#include <stdio.h>#include <stdlib.h>#include <memory.h>struct student generate(char name[], int age, int gender);void foo(void);struct student{ // 我指定的是32位,而非64位 char *name; // name (指针4字节) 存储的是字符串指针也就是字符串的内存地址 unsigned int age; // age (unsigned int 4字节) unsigned int gender; // gender (unsigned int 4字节)}; /*无论如何赋值结构体sizeof都是12字节*/struct student generate(char name[], int age, int gender){ char *ming = name; struct student xiaoming = { ming, age, gender}; printf("%s %d\n", name, sizeof(xiaoming)); printf("%d\n", *(unsigned int *)((unsigned int)&xiaoming + 4)); // 骚操作,拆解 // 目的是取结构体的第二个结构变量 // 1. &xiaoming 取结构体的指针即内存地址,起始内存地址 // 2. (unsigned int)&xiaoming 类型转换,方便加步长来寻址,如同汇编 // 3. (unsigned int)&xiaoming + 4 加上步长来寻址,步长位字节。这里是加上4字节,因为第一个结构体变量长度就是4字节,加上这个长度步长,跳过第一个结构体变量。 // 4. (unsigned int *)((unsigned int)&xiaoming + 4)) 得到第二个结构体变量内存地址后,类型转换为(unsigned int *)的指针 // 5. *(unsigned int *)((unsigned int)&xiaoming + 4)) 最后取指针地址,得到第二个结构体变量 return xiaoming;}void foo(void){ // char n[] = "哈哈"; generate("xiaoming", 16, 1); generate("xiaoli", 18, 1); generate("hahahahahahhahahahahahahahahahahahahahahhahaha", 20, 1); generate("hello my name is xiaoliu", 120, 1);}int main(int argc, char const *argv[]){ (void)argc; (void)argv; printf("struct\n"); foo(); system("pause"); return 0;}
memory.c
#include <stdio.h>#include <stdlib.h>#include <memory.h>#define PSGE_SIZE 4096struct student{ char *name; // name unsigned int age; // age unsigned int gender; // gender};void foo(void);void foo(void){ void *p = malloc(PSGE_SIZE); printf("0x%x\n", PSGE_SIZE); memset(p, 0, PSGE_SIZE); for (int i = 0; i < 13; i++) { printf("0x%x\n", *(int *)((unsigned int)p + i)); } struct student *s = (struct student *)p; printf("%x\n", sizeof(*s));}int main(int argc, char const *argv[]){ (void)argc; (void)argv; printf("struct\n"); foo(); system("pause"); return 0;}