接上一篇博客,我们来继续啃下指针这块“硬骨头”。
目录
2、形参的部分可以写成指针的形式,也可以写成数组的形式,但本质上都是指针形式,写成数组的形式是为了方便理解
1、 指针变量也是变量,是变量就有地址,那么指针变量的地址放在哪里呢?这就是我们在这一部分讨论的问题。
一、assert断言
assert.h头文件定义了宏assert(),用于在运行时确保程序符合指定条件,如果不符合则报错终止运行,这个宏常常被称为“断言”。
assert(p != NULL);
当运行到这一句时,验证p是否为NULL,若不等于NULL,则继续运行;若等于则报错终止运行。
assert()宏接收一个表达式为参数,如果表达式为真,assert()不会产生任何作用,程序继续运行;表达式为假,assert()就会报错。
通过以上两个代码我们就可以看到assert()的作用了。
当我们确定程序没有问题的时候,不需要断言的时候,我们就可以禁用断言,使用#define NDBUG指令。
但是assert()也是有缺点的,它引入了额外的检查,增加了程序的运行时间。
二、指针的使用和传址调用
1、strlen的模拟实现
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char *p)
{
size_t count = 0;
assert(p!=NULL);
while (*p)
{
count++;
p++;
}
return count;
}
int main()
{
char arr[] = "abcde";
size_t len = my_strlen(arr);
printf("%zd\n", len);
return 0;
}
//运行结果为 5
2、传值调用和传址调用
对于这个问题,我们用一道例题来进行解释
写一个函数来交换两个整型变量的值
我们先不用函数来实现一下这个功能,代码如下:
接下来就是使用函数了,我们定义Swap函数为交换函数:
代码如下:
很神奇,为什么没有交换过来呢?这是什么原因呢?三秒钟时间考虑一下。
3
2
1
好,时间到,我刚开始看到这个代码没有成功实现函数功能也很吃惊,直到我懂得了其中的道理之后就明白了自己的错误,这道题的问题就是咱们的标题:传值调用与传址调用。
接下来,就让我们一起来解决这个问题吧!
我们可以看到,a和 b是实参,x和y是形参,当实参传递给形参的时候,形参是有自己独立的空间的,形参是实参的一份临时拷贝,对形参的修改,不会影响实参。
所以,下面的代码才是正确的:
三、数组名的理解
通过下面的代码可以知道,数组名是数字首元素的地址。
但是,这里是有两个例外的:
(1)sizeof(数组名),sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节;
(2)&数组名,这里的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组 首元素的地址是有区别的);
除此之外,任何地方使用数组名,数组名都表示首元素的地址。
四、使用指针访问数组
上面的代码还可以改为这样
五、一维数组传参的本质
1、 一维数组传参的时候,传过去的是数组首元素的地址
2、形参的部分可以写成指针的形式,也可以写成数组的形式,但本质上都是指针形式,写成数组的形式是为了方便理解
六、冒泡排序(两两相邻元素进行比较)
1、普通方法
#include<stdio.h>
void bubble_sort(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int j = 0;
for (j = 0; j < sz - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
运行结果如下:
2、指针形式
#include<stdio.h>
void bubble_sort(int *arr, int sz)
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int j = 0;
for (j = 0; j < sz - i - 1; j++)
{
if (*(arr + j) > *(arr + j + 1))
{
int tmp = *(arr + j);
*(arr + j) = *(arr + j + 1);
*(arr + j + 1) = tmp;
}
}
}
}
int main()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
3、升级高效版冒泡排序
#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[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
七、二级指针
1、 指针变量也是变量,是变量就有地址,那么指针变量的地址放在哪里呢?这就是我们在这一部分讨论的问题。
二级指针变量就是用来存放一级指针变量的地址的
2、使用:
八、指针数组------存放指针的数组
指针数组模拟二维数组
arr[i]访问的是arr数组的元素,arr[i]指向了整形一维数组,arr[i][j]就是整形一维数组中的元素。
#include<stdio.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 3,4,5,6,7 };
int arr3[] = { 5,6,7,8,9 };
int* arr[3] = {arr1, arr2, arr3};
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
运行结果如下:
到这里C语言指针第二部分就结束了,我们又学习到了许多未曾听说过的知识,就让我们好好学习,多多复习,继续在指针的世界里遨游把!