C语言的指针(二)

 4.const修饰指针
    4.1const关键字

    1):const修饰普通变量

int main()
{
    const int num = 0;
    num = 20;
    printf("%d",num);
    return 0;
}

    如上图所示代码,当我们用const修饰num后,试图更改num的值并运行时,会出现以下报错:

     由此可见,被const修饰的普通变量,其内容无法被直接修改。

    注:C语言中,这里的num为常变量(本质仍为变量),因为有const修饰,编译器在语法上不允许直接修改这一变量;而C++中,这里的num为常量

    但是,当我们通过指针,间接地修改num的值时,会发现程序一切正常。如下图所示:

#include <stdio.h>
int main()
{
    const int num = 0;
    int* pn = &num;
    *pn = 20;
    printf("%d", num);
    return 0;
}

 

    因此,对于const修饰的普通变量来说,它自己不能被直接的修改,但是我们可以用指针去间接的修改它。

    2):const修饰指针变量

    通常来讲,const修饰指针变量有两种情况(假设 pi 是 i 的指针):

    (1)const放在 * 左边:int const * pi:这种情况下,可以理解为const修饰的是 *pi(对 pi 解引用后就是 i ) ,因此指针指向的内容(即 i 的内容)就不能修改。

    (2)const放在 * 右边:int * const pi:这种情况下,可以理解为const修饰的是 pi (指针变量本身的内容),因此指针指向的内容(即 i 的地址)就不能修改。

注:特殊的,若两个地方均有const修饰,那么 pi 和 *pi 均不能被修改(即 i 的地址和内容)。

5.指针运算
    5.1指针+/-整数

    指针+/-整数的实际含义,我们已经在《C语言的指针(一)》中学习过了,这里我们就以一个实际的例子来加深我们的理解,我们将通过指针完成对数组内元素的打印:

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int* parr = &arr[0];//创建一个指针变量,指向数组的首元素
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数
	for (int i = 0; i <= sz - 1; i++)
	{
		printf("%d ", *(parr + i));
	}

	return 0;
}

附运行截图:

    5.2指针-指针(地址-地址)

    1):先出结论:指针-指针(的绝对值),得到的是指针和指针间的元素个数。我们可以如下图代码尝试一下:

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("%2d\n", &arr[9] - &arr[0]);
	printf("%2d\n", &arr[0] - &arr[9]);

	return 0;
}

附运行截图:

注:这种运算的前提条件是:两个指针必须指向同一块空间(比如同一个数组内) 

    5.3指针的关系运算

    1):自己尝试实现strlen函数。

    在这之前,我们需要学习两个知识点:

    (1)strlen函数用于求字符串的字符个数,即 ‘ \0 '之前的字符个数(每个字符串末尾都有 ' \0 ' 用来表示字符串的结束)。

    (2)数组名实际上就是数组首元素的地址。

  接下来,我们着手实现这一函数:

#include <stdio.h>
size_t strlen_self(char* arr)
{
	char* s =arr ;
	size_t count = 0;
	while (*s != '\0')
	{
		s++;//跳到下一个字符
		count++;//计数
	}
	return count;
}
int main()
{
	char arr[] = "abcdef";
	printf("%zd", strlen_self(arr));
}

6.野指针
    6.1概念

    野指针即指向的位置是不可知的(随机的、不正确的、没有明确限制的)的指针。

    6.2成因

    1):指针未初始化

include <stdio.h>
int main()
{
	int* p ;//p没有初始化p里面的地址为随机值
	*p = 20;//p指向的空间不属于这一程序,形成了非法访问
	printf("%d", *p);
	return 0;
}

    2): 指针越界访问

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	int* p = &arr[0];
	int i = 0;
	for (i = 0; i <= 11; i++)
	{
		*p = i;
		p++;//i==11时,指针超出了数组范围,越界访问形成了野指针
	}
	return 0;
}

    3):指针指向的空间释放了 

#include <stdio.h>
int* test()
{
	int n = 100;
	return &n;
}
int main()
{
	int* p = test();//p指向的空间被释放了,那块空间可能已经不属于该程序了
	printf("%d\n", *p);
	return 0;
}
    6.3如何规避野指针

    1):指针初始化:如果明确知道指针指向哪里,就直接赋地址,若不能,则可以给指针赋值NULLNULL是C语言中定义的一个标识符常量,值是0,0也是地址,但这个地址是无法使用的,读写该地址会报错。

int n = 0;
int* p1 = &n;
int* p2 = NULL;//NULL空指针

*关于0:0—数字—0、’ 0 ‘—字符0 —ASCII值为48、’ \0 ’—转义字符—0、NULL—空指针—0

    2):小心指针越界:一个程序申请了哪些内存空间,指针就只能访问这些内存空间,不能超出范围访问,超出了就是越界访问。

    3):指针变量不再使用时,及时置NULL,指针使用前检查其有效性。

    当指针变量指向一块区域时,我们可以通过指针访问该区域,后期不再使用这个指针访问空间时,我们可以将该指针置为NULL。因为我们写代码时约定俗成的一个规则就是:只要是NULL指针就不去访问,同时使用指针之前判断指针是否为NULL

    4):避免返回局部变量的地址

7.assert断言

    assert.h头文件定义了 “ 宏assert(表达式)” ,用于在运行时确保程序符合指定条件。如果不符合,就报错终止运行。这个宏常常被称为“断言”。例如:

assert( p != NULL )

    assert能自动标识出出错文件及行号,且无需改代码就能开启/关闭。关闭assert(   )的机制如下:

#define NDEBUG

但是其缺点为:引入了额外检查,增加了运行时间。 

                                                                                                                              ——指针(二)完

    

    

     

         

     

 

 

    

 

 

     

 

 

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值