代码解析
int main()
{
int i = 0;
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (i = 0;i <= 12;i++)
{
arr[i] = 0;
printf("hehe\n");
}
return 0;
}
i,arr是局部变量,放在内存中的栈区,栈区先使用高地址,再用低地址,内存——栈区,堆区,静态区,假设上面是高地址,也可以反过来画,先创建i,数组随下标增长,地址由低到高,
不同的编译器和环境下i和arr中间的空间不一样
vs2019环境恰好两个整形
vc6.0i和arr之间没有多余的空间
gcci和arr之间有一个整形的空间
越界访问会报错,死循环忙着没时间报错,
releasse版本i在arr下面,越界访问也不会访问i,不会覆盖,没有死循环,
strcpy两种写法
char * my_strcpy(char* dest, const char* src)
{
//空指针非常危险,传参空指针解引用出问题,读取访问异常,要保证函数用的指针有效
//但是传空指针过来会把问题隐藏,直接返回什么事都不干,程序员不知道传了空指针
//缺点:if语句每次都要执行(debug和release版本)
if ((dest == NULL) || (src == NULL));
{
return;
}
char* p = dest;
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
return p;
}
//如果两个数组传反了,p常量字符串不能改的,反向拷贝
//避免问题,src前加const,报错表达式必须为可修改的左值,编译不过去,
//保护源头数据先把编译问题暴露,不至于为运行式问题,
char* my_strcpy(char* dest, const char* src)
{
//可以用断言assert,放表达式,指针表达式,其他表达式……,
//&&前面为0后面不算,表达式假就报错,真就什么都不发生,判断表达式真假,断言指针有效性,报错在文件几行,快速定位问题
//assert在release版本优化,自行解决空指针问题,不需要assert,
assert(dest && src);
char* p = dest;
while (*dest++ = *src++)
{
;
}
return p;
//strcpy返回目标空间起始地址,dest修改后不再指向起始地址,先保存一份dest
}
const修饰变量的两种形式
int num = 10;
int * p = #
*p = 20;//num是变量,可以修改,通过指针p
//num = 20;//直接改
const int num = 10;//const希望num不能改
num = 20;//err,左值不可修改
int* p = #
*p = 20;//right其实是漏洞,通过指针把num修改了
1,const在*左边
int n = 30;
int num2 = 20;
const int* p = &num2;//const在*左边
int const* p = &num2;//const在*左边,限制(*p)
*p = 30;//err,左值为const,p指向的内容不能修改,成功保护了num
p = &n;//right,p本身可以修改存放其他地址
2,const在*右边
int n = 20;
int num3 = 40;
int* const p = &num3;//const在*右边,const限制p
*p = 50;//right,*p不受限制,可以修改,其实没能保护数据num
p = &n;//err,p不能修改指向其他变量,