深入理解指针(3)

本文探讨了C语言中的assert断言用法,强调其在确保代码正确性的角色,以及指针的传值调用和传址调用的区别,特别是在交换变量和数组元素时。同时揭示了数组名的特殊性质,如sizeof和&运算符的作用,以及如何通过指针直接访问数组元素以提高编程效率。
摘要由CSDN通过智能技术生成

1.assert断言

这里先说一下assert断言是什么:assert.h头文件定义了assert(),用于在运行时确保程序符合指定条件,如果不符合就报错终止运行。这个常常被称为“断言”。

那简单来说assert其实就是用来中断不符合条件的情况。

assert(p != NULL);

 就像上述代码一样,如果p !=NULL就会继续往下进行,如果p=NULL程序就会终止,并且给出报错提示,并且还会给出错在哪个位置。是不是特别好用。如果不能理解没关系这里给串代码。

 因为这里的p = &a不等于NULL这里就是对的能继续执行下去,那下面再给个等于NULL的代码

到这里就报错了,而且还给了你错误的地方,多好 。如果己经确认程序没有问题,就不用再做断言了,就在#include<assert.h>前面定义一个宏NDEBUG写法是这样#define NDEBUG

但是这个assert也是有缺点的就是引入了额外的检查,增加了程序运行时间。所以

学习了assert我们要学着去优化一下之前的代码,比如之前的strlen求字符串长度的代码,优化如下 :

 

对比这两张图片我们可以看出来第一点就是加了assert 断言,使代码的安全性更进了一步。假如说,有人不小心把arr改成NULL那么传给s的也是NULL,那么有了这个assert就很安全了。

还有一点就是const保证了*s不会被不良修改。再一个就是size_t,size_t是无符号整型假如返回值是负数那么有了size_t就不会担心负数问题。

2.指针的使用和传址调用 

2.1传值调用和传址调用

我们学指针是为了解决问题的,但什么问题是非指针不可呢?

例如;写一个函数交换两个整型变量的值

根据我们的理解而且是不用指针写出来的是这样的:想创建第三个变量来进行两个值的转换。

swap1函数在这个时候,是把变量本身直接传递给函数,这种调用函数的方式就是传值调用

但是呢,这样却没有交换了位置,为什么呢 ?

 这里的ab地址和xy的地址不同,所以形参的交换对实参没有影响。

因为实参传递给形参的时候,形参会单独创建一份临时空间来接受实参,对形参的修改不影响实参 。

所以我们要怎么修改呢?这时就要用到指针了。

这里怎么理解呢?

这里传上去的是a和b的地址 ,我们知道创建一个变量的话,他们的地址都是随机的,但是呢,变量在销毁之前只要知道这个地址,那么这个变量就是可以访问的。而这里我们用int *px和int *py来接收&a和&b,就会使形参和实参的地址是一样的,而一样的话就会使形参转换实参也会给跟着转换。这就是传址调用

                                                  下面是讲数组与指针的关系

3.数组名的理解

我们之前就知道数组名就是首元素的地址,地址上arr是等于&arr[0]的,但是这里有个疑问:

这串代码输出是40啊,如果是首元素的地址的话不应该是4或者8吗,为啥这里不一样呢? 

其实数组名是首元素的地址这句话是对的,但是有两个例外:

sizeof(数组名),sizeof中单独放数组名,这里的数组名表示的是整个数组,计算的是整个数组的大小,单位是字节,

&数组名,这里的数组名表示的是整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)。

初次之外,任何地方使用数组名,数组名都表示首元素的地址。

这里补充几点,嘎嘎重点:  &arr   是数组名取地址:
  &arr   是对这个指针取地址,得到的是一个指向数组类型(数组元素类型和数组长度的复合类型)的指针。
  &arr[0]   是直接对数组首元素取地址:
这样做是明确表示你想获取数组第一个元素的地址。
  &arr[0]   得到的是一个指向数组第一个元素的指针。
在大部分情况下,当你需要对数组元素进行操作时,应该使用   &arr[0]  。
简单来说,虽然&arr和&arr[0]值上是相同的(都是数组的起始地址),但是从语义上讲,  &arr[0]   更清晰地表达了操作的意图,即获取数组的第一个元素的地址。这在进行指针运算或者作为函数参数传递时尤为重要。

我们在上面知道了arr和&arr和&arr[0]在值上是一样的都是数组起始地址但是是有区别的这里给串代码

 这里我们发现&arr[0]和&arr[0]+1像差4个字节,arr和arr+1也是相差4个字节,是因为&arr[0]和arr都是首元素地址,+1就是跳过一个元素。

但是&arr和&arr+1相差40个字节,这就是&arr是数组地址,+1操作是跳过整个数组的。

但是这里的40是怎么算出来的呢?首先我们知道打印出来的地址是16进制的数,他们相差28,要把28转化成10进制的数就是40,这才是它们之间的地址真实差值,28只是在16进制是28并不是正儿八经的数差。

4.使用指针访问数组

什么是使用指针访问数组呢?

在编程中,使用指针访问数组通常意味着直接通过内存地址来访问数组元素,而不是通过数组索引。在C语言中,这种操作比较常见,因为C语言提供对内存的直接控制。

#include <stdio.h>
int main()
{
     int arr[10] = {0};

     int i = 0;
     int sz = sizeof(arr)/sizeof(arr[0]);

     int* p = arr;
       for(i=0; i<sz; i++)
   {
        scanf("%d", p+i);
     //这里的p+i可以写成arr+i
   }  

      for(i=0; i<sz; i++)
   {
        printf("%d ", *(p+i));
   }
 return 0;
}

这串代码就是使用指针访问数组

我们再来分析一下:

*(p+i)=*(arr+i) *(arr+i) = arr[i]而且p是指针变量这里面存放着arr的地址所以p = arr

所以arr[i] = p[i]还有神奇的*(arr + i)= *(i + arr)满足交换律因为*(arr+i)= arr[i]所以*(i+arr)= i[arr]真是神奇啊!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值