免费行业网站源码,湖南人文科技学院招生网,网站404 模板,做公司网站怎么删除图片大家好啊#xff0c;我是小象٩(๑ω๑)۶ 我的博客#xff1a;Xiao Xiangζั͡ޓއއ 很高兴见到大家#xff0c;希望能够和大家一起交流学习#xff0c;共同进步。 今天我们来对上一节做一些小补充#xff0c;了解学习一下assert断言#xff0c;指针的使用和传址调用… 大家好啊我是小象٩(๑òωó๑)۶ 我的博客Xiao Xiangζั͡ޓއއ 很高兴见到大家希望能够和大家一起交流学习共同进步。 今天我们来对上一节做一些小补充了解学习一下assert断言指针的使用和传址调用等… 目录 一、assert 断言二、指针的使用和传址调用2.1 strlen的模拟实现2.2 传值调用和传址调用 一、assert 断言
assert 断言是一种在程序中用于检查某个条件是否为真的语句。它基于这样的假设在程序的某个特定点上某个条件应该始终成立。如果这个条件确实为真程序将继续正常执行但如果条件为假断言就会失败通常会导致程序抛出一个AssertionError 异常从而中断程序的执行。这有助于快速定位程序中的错误尤其是在开发和测试阶段。 assert.h 头文件定义了宏 assert() 用于在运行时确保程序符合指定条件如果不符合就报错终止运行。这个宏常常被称为“断言”。 作用 调试辅助帮助开发者快速定位程序中的逻辑错误。例如在一个计算平均值的函数中可以使用断言来确保传入的列表不为空因为计算空列表的平均值是没有意义的这能让开发者在函数被错误调用时迅速发现问题。 代码契约在编写函数或方法时断言可以用于定义函数的前置条件和后置条件形成一种代码契约。比如一个除法函数使用断言可以确保除数不为零这个前置条件明确函数的使用规则也让其他阅读和使用代码的人清楚函数的约束条件。 测试验证在测试用例中断言是验证测试结果是否符合预期的重要手段。比如在单元测试中使用断言来检查函数的返回值是否等于预期值或者检查某个对象的属性是否处于特定状态从而判断测试是否通过。 assert(p ! NULL);上面代码在程序运行到这一行语句时验证变量 p 是否等于 NULL 。如果确实不等于 NULL 程序继续运行否则就会终止运行并且给出报错信息提示。 assert() 宏接受⼀个表达式作为参数。如果该表达式为真返回值⾮零 assert() 不会产生任何作用程序继续运行。如果该表达式为假返回值为零 assert() 就会报错在标准错误流 stderr 中写入一条错误信息显示没有通过的表达式以及包含这个表达式的文件名和行号。 assert() 的使用对程序员是非常友好的使用assert() 有几个好处它不仅能自动标识文件和出问题的行号还有一种无需更改代码就能开启或关闭 assert()的机制。如果已经确认程序没有问题不需要再做断言就在 #include assert.h 语句的前面定义⼀个宏 NDEBUG 。 #define NDEBUG
#include assert.h然后重新编译程序编译器就会禁用文件中所有的 assert() 语句。如果程序又出现问题可以移除这条 #define NDEBUG 指令或者把它注释掉再次编译这样就重新启用了 assert() 语句。 assert() 的缺点是因为引入了额外的检查增加了程序的运行时间。 一般我们可以在 Debug 中使用在 Release 版本中选择禁用 assert 就行在 VS 这样的集成开发环境中在 Release 版本中直接就是优化掉了。这样在debug版本写有利于程序员排查问题在 Release 版本不影响用户使用时程序的效率。
二、指针的使用和传址调用
2.1 strlen的模拟实现
库函数strlen的功能是求字符串长度统计的是字符串中 \0 之前的字符的个数。 函数原型如下
size_t strlen ( const char * str );参数str接收一个字符串的起始地址然后开始统计字符串中 \0 之前的字符个数最终返回长度。 如果要模拟实现只要从起始地址开始向后逐个字符的遍历只要不是 \0 字符计数器就1这样直到 \0 就停止。 举个例子:
int my_strlen(const char* str)
{int count 0;assert(str);while (*str){count;str;}return count;
}
int main()
{int len my_strlen(abcdef);printf(%d\n, len);return 0;
}2.2 传值调用和传址调用
学习指针的目的是使用指针解决问题那什么问题非指针不可呢 例如写一个函数交换两个整型变量的值 我们可能写出这样的代码
#include stdio.h
void Swap1(int x, int y)
{int tmp x;x y;y tmp;
}
int main()
{int a 0;int b 0;scanf(%d %d, a, b);printf(交换前a%d b%d\n, a, b);Swap1(a, b);printf(交换后a%d b%d\n, a, b);return 0;
}我们发现其实没产生交换的效果这是为什么呢 在这个代码里Swap1 函数采用的是传值调用。传值调用的特点是函数接收的是实参的副本而不是实参本身。具体来说 在 main 函数中调用 Swap1(a, b) 时a 和 b 的值会被复制一份分别传递给 Swap1 函数的形参 x 和 y。 在 Swap1 函数内部虽然 x 和 y 的值进行了交换但这只是对副本的操作并不会影响到 main 函数中原始的 a 和 b 的值。
结论实参传递给形参的时候形参会单独创建一份临时空间来接收实参对形参的修改不影响实参。 所以Swap1是失败的了。
那怎么办呢 我们现在要解决的就是当调用Swap函数的时候Swap函数内部操作的就是main函数中的a和b直接将a和b的值交换了。那么就可以使用指针了在main函数中将a和b的地址传递给Swap函数Swap函数里边通过地址间接的操作main函数中的a和b并达到交换的效果就好了。 像这样
#include stdio.h
void Swap2(int* px, int* py)
{int tmp 0;tmp *px;*px *py;*py tmp;
}
int main()
{int a 0;int b 0;scanf(%d %d, a, b);printf(交换前a%d b%d\n, a, b);Swap2(a, b);printf(交换后a%d b%d\n, a, b);return 0;
}我们可以看到实现成Swap2的方式顺利完成了任务这里调用Swap2函数的时候是将变量的地址传递给了函数这种函数调用方式叫传址调用。 传址调用可以让函数和主调函数之间建立真正的联系在函数内部可以修改主调函数中的变量所以未来函数中只是需要主调函数中的变量值来实现计算就可以采用传值调用。如果函数内部要修改主调函数中的变量的值就需要传址调用。
好了这节内容便结束了,附上这两节所写的代码
#define _CRT_SECURE_NO_WARNINGS
#include stdio.h//int main()
//{
// int a 10;
// //int* pa a;//int*
// //char* pc a;
// void* pv2 a;
// //*pv2;
// //pv2;
//
// char ch w;
// //char*pc ch;
// //int* pi ch;
// void* pv ch;//char*
// //*pv;//err
// return 0;
//}//void test(void* pv)
//{
// //pv在使用的时候会强制类型转换然后去使用
// //
//}
//
//
//int main()
//{
// int a 10;
// test(a);
// char c w;
// test(c);
// double d 3.14;
// test(d);
//
// return 0;
//}//int main()
//{
// int arr[10] { 1,2,3,4,5,6,7,8,9,10 };
// int i 0;
// int sz sizeof(arr) / sizeof(arr[0]);//10
// int* p arr[0];
//
// //for (i 0; i sz; i)
// //{
// // *(p i) 0;
// //}
//
// for (i 0; i sz; i)
// {
// scanf(%d, p i);
// }
//
//
// for (i 0; i sz; i)
// {
// printf(%d , *(p i));
// }
//
// return 0;
//}//int main()
//{
// int arr[10] { 1,2,3,4,5,6,7,8,9,10 };
// int i 0;
// int sz sizeof(arr) / sizeof(arr[0]);//10
// int* p arr[sz-1];
//
// for (i 0; i sz; i)
// {
// *(p - i) i1;
// }
//
// for (i 0; i sz; i)
// {
// printf(%d , arr[i]);
// }
//
// return 0;
//}
//
//int main()
//{
// int arr[10] { 1,2,3,4,5,6,7,8,9,10 };
// int i 0;
// int sz sizeof(arr) / sizeof(arr[0]);//10
// int* p arr[sz - 1];
//
// for (i 0; i sz; i)
// {
// *p i 1;
// p--;
// }
//
// for (i 0; i sz; i)
// {
// printf(%d , arr[i]);
// }
//
// return 0;
//}//int main()
//{
// int arr[10] { 0 };
// int n arr[0] - arr[9];
// printf(%d\n, n);
//
// return 0;
//}//int main()
//{
// int arr[10] { 0 };
// char ch[5] {0};
// printf(%d\n, arr[9] - ch[0]);//err
//
// return 0;
//}#include string.h
//strlen 是求字符串长度统计的是字符串中\0之前的字符个数//int main()
//{
// char arr[] abcdef;
// //a b c d e f \0
// //数组名其实是数组首元素的地址
// //arr arr[0]
// size_t len strlen(arr);//6
// printf(%zd\n, len);
//
// return 0;
//}//size_t my_strlen(char* str)
//{
// size_t count 0;
// while (*str ! \0)
// {
// count;
// str;
// }
// return count;
//}
//
//size_t my_strlen(char* str)
//{
// char* start str;
// while (*str ! \0)
// str;
// return str - start;//指针-指针
//}
//
//
//int main()
//{
// char arr[] abcdefghi;
// //a b c d e f \0
// //数组名其实是数组首元素的地址
// //arr arr[0]-- char*
// size_t len my_strlen(arr);//6
// printf(%zd\n, len);
//
// return 0;
//}
////
//int main()
//{
// int arr[] { 1,2,3,4,5,6,7,8,9,10 };
// int sz sizeof(arr) / sizeof(arr[0]);
// int* p arr;
// while (p arr[sz])
// {
// printf(%d , *p);
// p;
// }
//
//
//
// //int i 0;
// //int* p arr;//p arr[0];
// //for (i 0; i sz; i)
// //{
// // printf(%d , *(p i));
// //}
//
//
// //for (i 0; i sz; i)
// //{
// // printf(%d , arr[i]);
// //}
//
//
// return 0;
//}//const 是常属性-不能改变的属性//int main()
//{
// const int a 10;
// //a变成了常变量a的本质还是变量但是因为被const修饰所以不能改变
// //a 1;//err
// int* p a;
// *p 1;
//
// printf(%d\n, a);
//
// return 0;
//}//int main()
//{
// const int n 10;
// int arr[n];
//
// return 0;
//}//int main()
//{
// const int a 10;
// //a变成了常变量a的本质还是变量但是因为被const修饰所以不能改变
// //a 1;//err
// const int* p a;
// *p 1;
//
// printf(%d\n, a);
//
// return 0;
//}//const 修饰指针变量
//可以放在*的左边也可以放在*的右边,意义是不一样的
//const 放在*的左边表示指针指向的内容不能通过指针来改变了但是指针变量本身是可以改变的
//const 放在*的右边表示指针变量本身不能被修改了但是指针指向的内容是可以通过指针变量来改变的//int main()
//{
// int a 100;
// int b 1000;
// int* const p a;
// *p 0;//ok
// p b;//err
//
// return 0;
//}//int main()
//{
// int a 100;
// int b 1000;
// const int * p a;
// //*p 0;//err
// p b;
//
// return 0;
//}//int main()
//{
// int a 100;
// int b 1000;
//
// const int* const p a;
//
// return 0;
//}
//
//
//
////int main()
//{
// int* p;//局部变量不初始化的时候里边放的是随机值
//
// *p 20;//非法访问p就是野指针
//
// return 0;
//}//int main()
//{
// int arr[10] { 1,2,3,4,5,6,7,8,9,10 };
// int* p arr;
// int sz sizeof(arr) / sizeof(arr[0]);
// int i 0;
// for (i 0; i sz; i)
// {
// *p i;
// p;
// }
//
// return 0;
//}
////
//int* test()
//{
// int n 100;
// return n;
//}
//
//int main()
//{
// int* p test();
// printf(%d\n, *p);
//
// return 0;
//}//
//int main()
//{
// int* p NULL;
// if(p ! NULL)
// *p 200;
//
// return 0;
//}
//#define NDEBUG
#include assert.h//int main()
//{
// int arr[10] { 1,2,3,4,5 };
// int* p arr;
// assert(p ! NULL);
// int i 0;
// for (i 0; i 5; i)
// {
// printf(%d , *p);
// p;
// }
// //
// return 0;
//}//int main()
//{
// int arr[10] { 1,2,3,4,5 };
// int* p arr;
// assert(p ! NULL);
// int i 0;
// for (i 0; i 5; i)
// {
// printf(%d , *p);
// p;
// }
//
// return 0;
//}//int main()
//{
// int a 5;
// assert(a ! 5);
//
// return 0;
//}
//
//size_t my_strlen(const char* str)
//{
// size_t count 0;
// assert(str ! NULL);
//
// while (*str)//\0 -- 0
// {
// count;
// str;
// }
// return count;
//}
//
//int main()
//{
// char arr[] abcdef;
// size_t len my_strlen(arr);
// printf(%zd\n, len);
//
// return 0;
//}//void Swap1(int x, int y)
//{
// int z 0;
// z x;
// x y;
// y z;
//}
//
//int main()
//{
// int a 0;
// int b 0;
// scanf(%d %d, a, b);
// //写一个函数交换a和b的内容
//
// printf(交换前:a %d b %d\n, a, b);
// Swap1(a, b);
// printf(交换后:a %d b %d\n, a, b);
//
// return 0;
//}//int main()
//{
// int a 10;
// int* p a;
// *p 20;
// return 0;
//}//void Swap2(int* pa, int* pb)
//{
// int z 0;
// z *pa;//z a
// *pa *pb;//a b
// *pb z;//b z
//}
//
//int main()
//{
// int a 0;
// int b 0;
// scanf(%d %d, a, b);
// //写一个函数交换a和b的内容
//
// printf(交换前:a %d b %d\n, a, b);
// Swap2(a, b);
// printf(交换后:a %d b %d\n, a, b);
//
// return 0;
//}//int Add(int x, int y)
//{
// return x y;
//}
//
//int main()
//{
// int a 3;
// int b 5;
// int r Add(a, b);//传值调用
// printf(%d\n, r);
// return 0;
//}// 3 5
int Max(int x, int y)
{return (x y ? x : y);
}int main()
{int a 3;int b 5;int r Max(a, b);//传值调用printf(%d\n, r);return 0;
}