指针2.指针运算

今天我们大家一起来学习指针运算
在这里插入图片描述

1.指针运算

1.1指针± 整数

数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺藤摸瓜就能找到后⾯的所有元素

for(i=0; i<sz; i++)
{
	printf("%d ", *(p+i));//p+i 这⾥就是指针+整数
}

在这里插入图片描述

1.2指针-指针

//指针-指针
#include <stdio.h>
int my_strlen(char *s)
{
	char *p = s;//(将字符串首元素的地址传给指针p)
	while(*p != '\0' )//(当p地址等于\0时结束循环)
	p++;
	return p-s;//(得到字符串长度)
}
int main()
{
	printf("%d\n", my_strlen("abc"));
	return 0;
}

1.3指针的关系运算

//指针的关系运算
#include <stdio.h>
int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int *p = &arr[0];
	int sz = sizeof(arr)/sizeof(arr[0]);
while(p<arr+sz) //指针的⼤⼩⽐较
{
	printf("%d ", *p);//打印数组的每个元素
	p++;
}
return 0;
}

2.野指针

2.1 概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

2.2指针未初始化

#include <stdio.h>
int main()
{
	int *p;//局部变量指针未初始化,默认为随机值
	*p = 20;
	return 0;
}

2.3指针越界访问

#include <stdio.h>
int main()
{
	int arr[10] = {0};
	int *p = &arr[0];
	int i = 0;
for(i=0; i<=11; i++)
{
	//当指针指向的范围超出数组arr的范围时,p就是野指针
	*(p++) = i;
}
return 0;
}

2.4指针指向的空间释放(空间被收回)

#include <stdio.h>
int* test()
{
	int n = 100;
	return &n;
}
int main()
{
	int*p = test();
	printf("%d\n", *p);
	return 0;
}

3.规避野指针

NULL 是C语⾔中定义的⼀个标识符常量,
值是0,0也是地址,这个地址是无法使用的,读写该地址会报错。
只要是NULL指针就不去访问,
同时使用指针之前可以判断指针是否为NULL

4.assert 断言

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

assert(p != NULL);

它不仅能自动标识文件和出问题的行号,
还有⼀种无需更改代码就能开启或关闭 assert() 的机制

缺点是,因为引入了额外的检查,增加了程序的运行时间

5.传值调用和传址调用

写⼀个函数,交换两个整型变量的值

这里调用Swap2函数的时候是将变量的地址传递给了函数,
这种函数调用方式叫:传址调用。

#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;
}

传址调用,可以让函数和主调函数之间建立真正的联系,
在函数内部可以修改主调函数中的变量;
所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用。
如果函数内部要修改主调函数中的变量的值,就需要传址调用。

练习

1.字符串逆序

写一个函数,可以逆序一个字符串的内容。

代码


#include<stdio.h>
#include<string.h>

void Reverse(char* str)
{
	char* left = str;
	char* right = str + strlen(str) - 1;
	char tmp = { 0 };
	while (left < right)
	{
		tmp = *left;
		*left = *right;
		*right = tmp;
		left++;
		right--;
	}
}


int main()
{
	char arr[7] = "abcdef";
	printf("字符串逆序前:%s\n", arr);
	Reverse(arr);
	printf("字符串逆序后:%s\n", arr);
	return 0;
}

运行结果

在这里插入图片描述

2.调整奇数偶数顺序

输入一个整数数组,实现一个函数,
来调整该数组中数字的顺序
使得数组中所有的奇数位于数组的前半部分,
所有偶数位于数组的后半部分。

代码


#include<stdio.h>
#include<string.h>

void Swap_arr(int arr[], int sz)
{
	int left = 0;
	int right = sz - 1;
	int tmp = 0;
	while (left < right)
	{
		while ((left < right) && (arr[left] % 2 == 1))
		{
			left++;
		}
		while ((left < right) && (arr[right] % 2 == 0))
		{
			right--;
		}
		if (left < right)
		{
			tmp = arr[left];
			arr[left] = arr[right];
			arr[right] = tmp;
		}
	}
}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("调换奇数偶数数据前:\n");
	for (int i = 0; i < sz; i++)
	{	
		printf("%d ", arr[i]);	
	}
	printf("\n");
	Swap_arr(arr,sz);
	printf("调换奇数偶数数据后:\n");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

运行结果

在这里插入图片描述

3.strlen模拟实现

代码


#include<stdio.h>
#include<assert.h>

int Strlen(const char * str)
{
	int count = 0;
	assert(str);
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}

int main()
{
	int ret = 0 ;
	ret = Strlen("abcdef");
	printf("长度:%d\n", ret);
	return 0;
}

运行结果

在这里插入图片描述

总结

我们了解了指针的三种运算,知道野指针如何规避及assert断言
明白指针在自定义函数里的传址调用

对指针(指针运算,野指针,assert断言,传值调用)的分享就到这里了,如果感觉不错,希望可以给博主点个赞或者关注,感谢大家的支持,成为我继续分享的动力,还有什么问题和建议可以在评论区评论,拜拜。
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值