错题详解

int main()
{
int i = 0;
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
for (i = 0;i <= 12;i++)
{
arr[i] = 0;
printf("hehe\n");
}

return 0;
}

错误原因:数组地址指向了数组的外面



无限循环的原因:i创建在了arr的高位,arr往高位读取,将i里面的数字修改成了0,重新开始


数据存放在内存中时,是先放在高地址中,在往低地址中存放

然而数据读取,是从低地址往高地址中读取

vs2019在这个数组和变量的地址中间隔了2隔空地址

自己写一个strcpy(究极简化版)

#include<assert.h>
char my_strcpy(char* arr1,const char* arr2)
{
assert(arr1 != NULL);//断言
assert(arr2 != NULL);//判断如果括号里面的是真,就执行下面,不然会报错,直接打印到界面里面
int* ret = arr1;
while (*arr1++ = *arr2++)//当传过去/0的时候while判断括号里面都是假所以跳出
{
;
}
return ret;
}
int main()
{
char arr1[20] = "*********";
char arr2[] = "hello";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}

const的使用

语法使用

int main()
{
const int m = 10;//这里相当于把门封上了,但是靠地址可以空降到地方进行处理
int n = 100;
//int* p = &m;
//const int* p = &m;//这里是将*p即内容锁死,是内容无法更改
//也可以写成int const* p = &m
//p = &n;
//*p = 0;//err

//int * const p = &m;//这里是将p即地址锁死,使地址无法更改无法更改
//p = &n;//err
//*p = 0;

//int const* const p = &m;//这样也可以写,两个都没法改

printf("%d\n", m);
return 0;
}

自己的理解

int main()
{
int m = 10;
int n = 100;
const int* p = &m;
p = &n;//这里还是被改了只想的地方被改,内容会被改,但是直接更改内容还是不行
printf("%d\n", *p);
return 0;
}

实现strlen

#include<assert.h>
unsigned int my_strlen(const char* a)
{
assert(a != NULL);//断言的是空指针,而不是指针的内容
unsigned int count = 0;
while (*a++ != '\0')
{
count++;
}
return count;
}
int main()
{
char a[20] = "123";
int i=my_strlen(a);
printf("%d\n", i);
return 0;
}

实现assert

void my_assert(char* input)
{
if (0==input)
{
printf("此条件不成立\n");
}
}
int main()
{
int a = 0, b = 0;
int* i = a + b;
my_assert(i);
return 0;
}

奇怪的题

1、++和括号的优先级

int main()
{
int a = 0, b = 1, c = 0;
b = (++c,c++,++a, a++);//b=1,a=2;把括号去掉的话,会把c也加上
printf("%d %d\n", a, b);//这里输出2 1
return 0;
}
int main()
{
int a = 0, b = 1, c = 0;
b = ++c,c++,++a, a++;//b=1,a=2;把括号去掉的话,会把c也加上
printf("%d %d\n", a, b);//这里输出2 3
return 0;
}

2、+=和+的优先级

int main()
{
int i = 10;
int j = 30;
int k = 3;
k *= i + j;//'+'优先级大于*=
//等于k *= (i + j);
printf("%d\n", k);
return 0;
}

3、特殊语法和类型提升

int main()
{
/*int x = 123;
if (x = 0)//这里判定为假
{
printf("123");
}*/

//int year = 2021, * p = &year;
////等同于
//int year = 2021;
//int* p = &year;

char a;int b;float c;double d;
a* b + c - d;
//这里的结果类型是double
//a会先整型提升为int,a*b的类型会提升为double,再减去float,最后的结果还会是double
return 0;
}

用按位与来求,二进制有多少个1

int number1(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
int main()
{
int n = 15;
int ret = number1(n);
printf("%d\n", ret);
return 0;
}

解释

m 1111

m-1 1110

m 1110

m-1 1101

m 1100

m-1 1011

m 1000

m-1 0111

m 0000

这个算法会让m的二进制最右面的1消掉

看m和n中二进制各个位不一样的有多少

思路:1、先按位异或 2、在看结果有多少1

int number2(int n, int m)
{
int i = n ^ m;
int count = 0;
while (i)
{
i = i & (i - 1);
count++;
}
return count;
}
int main()
{
int m = 1;
int n = 0;
int ret = number2(n, m);
printf("%d\n", ret);
return 0;
}

思路:用%2/2的方式

int number3(int n)
{
int count = 0;
while (n)
{
if (1 == n % 2)
{
count++;
}
n = n / 2;
}
return count;
}
int main()
{
int m = 15;
int ret = number3(m);
printf("%d\n", ret);
return 0;
}

输入一个数,将他的二进制的奇数位和偶数位分别打印

int main()
{
int n = 15;
int i = 0;
//scanf_s("%d", &n);
//00000000 00000000 00000000 00001111
// 0000000 00000000 00000000 00001111
//从右向左的判别是否是偶数
//偶数
for (i = 31;i >= 1;i -= 2)
{
printf("%d ", (n >> i) & 1);
//在最后向右移动1位就是最开始从右向左的第二位,即第一个偶数位
}
printf("\n");
for (i =30;i >= 0;i -= 2)
{
printf("%d ", (n >> i) & 1);
}
return 0;
}

全局变量与局部变量遵从金字塔逻辑

即同级与同级之间没有联系,某一级只和他的上一级和下一级有联系

int a = 1;
void text()
{
int a = 2;
a += 1;
}
int main()
{
text();
printf("%d\n", a);
return 0;
}