1、统计二进制数中1的个数
#include <stdio.h>
int main(void)
{
int count = 0; //统计1出现次数
int x = 0b1011;
while(x)
{
count ++;
//x = 0b1011 => x-1 0b1010 x-1,将x从右往左数遇到第一个1变成0,左边全部变为1,右边不变
//x&x-1 == 1010 将x从右往左数,遇到第一个1变为0,其余为不变
x &= (x-1);
}
printf("%d\n", count);
return 0;
}
2、判断一个数是否是2的n次方
#include <stdio.h>
/*
2: 10
2-1: 01
2&(2-1): 00
4: 100
4-1: 011
4&(4-1): 000
8: 1000
8-1: 0111
8&(8-1): 0000
*/
#define ISPOWER_OF_TWO(x) (((x)&(x-1)) == 0)
int main(void)
{
int x = 0;
while(1)
{
printf("请输入一个数: ");
scanf("%d", &x);
if(1 == x)
{
printf("%d is not power of two\n", x);
}
else if(ISPOWER_OF_TWO(x))
{
printf("%d is power of two\n", x);
}
else
{
printf("%d is not power of two\n", x);
}
}
return 0;
}
3、实现字符串拷贝函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void* mystrcpy(char *dest, const char *src)
{
printf("dest存储的地址为:%#x src存储的地址为:%#x 当前行数%d\n", dest, src, __LINE__);
/*
1、q取出指针src下面的数据,赋值给dest
2、判断指针下的数据是否为0('\0')
3、指针里面存储的数据加1
*/
while(*dest++ = *src++);
printf("dest存储的地址为:%#x src存储的地址为:%#x 当前行数%d\n", dest, src, __LINE__);
}
int main(void)
{
char *src = "asdfg";
char *dest = (char *)calloc(1,256);
if(NULL == dest) //错误处理
{
perror("calloc函数申请堆内存失败");
}
printf("dest存储的地址为:%#x src存储的地址为:%#x 当前行数%d\n", dest, src, __LINE__);
mystrcpy(dest, src); //调用函数,将dest作为形参传入函数,函数结束后dest里面存储的数据(地址)不变
printf("dest存储的地址为:%#x src存储的地址为:%#x 当前行数%d\n", dest, src, __LINE__);
printf("src is %s\ndest is %s\n", src, dest);
return 0;
}
4、定义整形变量a,设置a的bit3,清除a的bit3
#include <stdio.h>
int main(void)
{
int a = 0b1111; //15
printf("a = %d\n", a);
//清除a的bit3,0111 ==》7
/*
1<<3 ==> 1000
~(1<<3) == > 0111
& ==> 0111
*/
a &= ~(1<<3);
printf("清除a的bit3,a = %d\n", a);
//设置a的bit3,1111 == 15
/*
1<<3 ==> 1000
1000
0111 (|)
1111
*/
a |= (1<<3);
printf("设置a的bit3,a = %d\n", a);
return 0;
}
5、sizeof运算符(不是函数)
#include <stdio.h>
int main(void)
{
int i = 10;
printf("i = %d\n", i);
printf("%zu\n", sizeof(i++)); //i++表达式不会运算
printf("i = %d\n", i);
return 0;
}
6、指针运算:指针+n = 地址+sizeof(指向的数据类型)*n
#include <stdio.h>
unsigned char *p1;
unsigned long *p2;
int main(void)
{
p1 = (unsigned char *)0x801000;
p2 = (unsigned long *)0x802000;
printf("%zu\n", sizeof(unsigned long)); //4
printf("%#x\n", p1+5); //0x801005 = 0x801000 + 1 * 5 = 0x801000 + sizeof(unsigned char) * 5
printf("%#x\n", p2+5); //0x802014 = 0x801000 + 4 * 5 = 0x801000 + sizeof(unsigned long) * 5
return 0;
}
7、volatile关键字,告知编译器变量可能会被意外改变,阻止编译器对其进行某些优化
8、a是数组,a与&a的区别
#include <stdio.h>
int main(void)
{
int a[5] = {1,2,3,4,5};
//&a表示整个数组的地址
printf("&a地址为: %p\n&a+1的地址为: %p\n", &a, &a+1);
//a,&a[0]均表示数组首元素地址
printf("数组a的地址为:%p\na+1的地址为: %p\n", a, a+1);
int *p1 = (int *)(&a + 1);
int *p2 = a;
printf("p1指向的地址: %p\np2指向的地址: %p\n", p1,p2);
printf("数组a有%zu个字节\n", sizeof(a));
return 0;
}
9、不使用第三参数,交换两个数
#include <stdio.h>
void swap(int *a, int *b)
{
*a = *a + *b;
*b = *a - *b; //==>*a+*b-*b=*a
*a = *a - *b; //==>*a+*b-*a=*b
}
int main(void)
{
int a = 3, b = 4;
printf("交换前a=%d, b=%d\n", a, b);
swap(&a, &b);
printf("交换后a=%d, b=%d\n", a, b);
return 0;
}
10、指针的内存空间,64位为8字节(64/8),32位为4字节(32/8)
#include <stdio.h>
int main(void)
{
printf("int *内存为%zu个字节\n",sizeof(int *));
printf("char *内存为%zu个字节\n",sizeof(char *));
printf("long *内存为%zu个字节\n",sizeof(long *));
printf("float *内存为%zu个字节\n",sizeof(float *));
return 0;
}
11、一级指针与二级指针
#include <stdio.h>
int main(void)
{
//str是一个数组,里面有4个数据,每个数据都是指针,该指针指向char
char *str[4] = {"ABCD", "EFGH", "IJKL", "MNOP"};
/*
*p => p是一个指针,存储数据是一个地址
**p => p是一个指针,存储数据是一个地址,该地址下面存储的数据还是一个地址
char **p => p是一个指针,存储数据是一个地址,该地址下面存储的数据还是一个地址,该地址下面存储的数据是char
*/
char **p = str;
printf("%s\n", *p);
}