1.assert断言:assert.h头文件定义了宏assert(),用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行。
#define NDEBUG
#include <assert.h>
使用assert的好处:能自动标识文件和出现的行号,还有一种无需更改代码就能开启或关闭assert()的机制。如果已经确定程序没有问题,就不需要做断言。
assert的缺点:因为引入额外的检查,增加了程序运行的时间。
2.指针的使用和地址调用
(1)strlen的模拟实现
库函数strlen的功能是求字符串长度,统计字符串\0之前的字符个数。函数原型如下:
size_t strlen ( const char * str );
参数str接收一个字符串的起始地址,然后开始统计字符串\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;
}
3.数组名的理解
数组名就是数组首元素(第一个元素的地址)
例如:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("&arr[0] = %p\n", &arr[0]);
printf("arr = % p\n", arr);
return 0;
}
输出结果:打印出来发现数组名和元素首地址是相同的。
有两个例外:
sizeof(数组名),sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
&数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
那么&arr和arr有什么区别?
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("&arr[0] = %p\n", &arr[0]);
printf("&arr[0]+1 = %p\n", &arr[0] + 1);
printf("arr = % p\n", arr);
printf("arr+1 = % p\n", arr + 1);
printf("&arr = % p\n", arr);
printf("&arr+1 = % p\n", arr + 1);
return 0;
}
输出结果:
& arr[0 = 0077F820
& arr[0] + 1 = 0077F824
arr = 0077F820
arr + 1 = 0077F824
& arr = 0077F820
& arr + 1 = 0077F848
&arr[0]和&arr[0]+1相差4个字节,arr和arr+1相差4个字节,是因为&arr[0]1和arr都是首元素的地址,+1就是跳过一个元素。
但是 & arr和 & arr + 1相差40个字节,这就是因为 & arr是数组的地址, + 1操作是跳过整个数组的。
数组名是数组⾸元素的地址,但是有2个例外。
4.一维数组传参的本质:数组传参传递的是首元素的地址。
5.冒泡法排序:两两相邻元素进行比较。
//冒泡法排序
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void bubble_sort(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz - 1; i++) {
int flag = 1;
int j = 0;
for (j = 0; j < sz - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
flag = 0;
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
if (flag == 1)
break;
}
}
int main()
{
int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
int i = 0;
for (i = 0; i < sz; i++) {
printf("%d ", arr[i]);
}
return 0;
}
运行之后:
6. 指针数组
指针数组是指针还是数组? 我们类⽐⼀下,整型数组,是存放整型的数组,字符数组是存放字符的数组。
那指针数组呢?是存放指针的数组
#include <stdio.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
//数组名是数组⾸元素的地址,类型是 int* 的,就可以存放在parr数组中
int* parr[3] = { arr1,arr2,arr3 };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
运行之后:
parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型⼀维数组,parr[i][j]就是整型⼀维数 组中的元素。 上述的代码模拟出⼆维数组的效果,实际上并⾮完全是⼆维数组,因为每⼀⾏并⾮是连续的。