总结一下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 8
void 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_H
typedef 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中的位1
bool 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 4096
struct 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;
}