C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

这篇具有很好参考价值的文章主要介绍了C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一.指针运算🌴

1.曾经用过的案例:写一个模拟实现字符串的函数

2.指针+-整数🌾

 3.指针-指针🌏

方法1:大地址-小地址或者小地址-大地址⛅

方法2:模拟实现指针相减🌱

4.指针的关系运算

二.指针和数组

☑️☑️​​​​​​​☑️​​​​​​​重点:

 💾画图笔记: 

1.指针和数组间的联系:

2.用指针访问二维数组

三.二级指针✅

🅿️对于二级指针的运算有:

四.指针数组

 🚩1.存放整型指针的数组

2.二级指针数组的应用

⁉️通过整型指针存放三个一维数组


一.指针运算🌴

1.曾经用过的案例:写一个模拟实现字符串的函数

前提说明:字符串在传参的时候,或者说作为一个表达式的时候,它的值是首字符的地址,它并不是把“abcdef”传给了my_strlen函数,而是把首字符'a'的地址传过去了,首字符'a'的地址是char类型的地址,需要一个char*的指针接收

#include<stdio.h>
int my_strlen(char* str)
{
	int count = 0;
	while (*str != '\0')
	{
		count++;
		//str++;//指针+整数
		str = str + 1;
 	}
	return count;
}
int main()
{
	int len = my_strlen("abcdef");
	printf("%d\n", len);

	return 0;
}

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

 思路:看str指向的那个字符是什么,不是‘\0’,计数器count++,指针str是一个char*的指针,+1跳过一个char类型的变量,最后当遇到'\0',返回count作为返回值。

2.指针+-整数🌾

#define N_VALUES 5
float values [ N_VALUES ];
float * vp ;
// 指针 +- 整数;指针的关系运算
for ( vp = & values [ 0 ]; vp < & values [ N_VALUES ];)
{
    * vp ++ = 0 ;
}

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

 3.指针-指针🌏

指针- 指针 == 地址 - 地址

前提:

  1. 两个指针指向同一块空间,指针的类型是一致的
  2. 指针 - 指针得到的是指针和指针之间的元素个数(这是语法规定的)

由前面我们可知指针+-整数是等于指针的,那如果指针 - 指针不就是整数了吗,分两种情况

方法1:大地址-小地址或者小地址-大地址⛅

1.大地址-小地址:随着数组下标的增长,地址是由低到高变化

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int n = &arr[9] - &arr[0];
	printf("%d\n", n);

	return 0;
}

执行: 

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

  • 为什么是9?答:语法规定。(但是还是不明白为什么是9)⛄

个人思路:把内存监视调出来:可以观察一下它们的地址 

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

🍄实践证明: 

用它们的地址相减:减出一个24,这个24是一个16进制数,可以代表它们之间相差的内存空间, 将16进制24转换为10进制后,是36byte也就是相差9个(整型)元素的地址空间

 2.小地址 - 大地址(特殊情况)

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int n = &arr[0] - &arr[9];
	printf("%d\n", n);

	return 0;
}

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

方法2:模拟实现指针相减🌱

int my_strlen(char* str)
{   
	char* start = str;
	while (*str!='\0')
	{
	
		str++;
	}
	return str - start;
}
int main()
{
	int len = my_strlen("abcdef");
	printf("%d\n", len);

	return 0;
}

执行:

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

 图解: 

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

4.指针的关系运算

for ( vp = & values [ N_VALUES ]; vp > & values [ 0 ];)
{
    *-- vp = 0 ;
}
经过修改之后的代码
for ( vp = & values [ N_VALUES - 1 ]; vp >= & values [ 0 ]; vp -- )
{
    * vp = 0 ;
}

关于这两种写法的理解:

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组关于野指针的知识:vp1:起始位置这不是越界了吗?没有。

🌵理解:

这个位置后面的空间虽然不属于values数组,但指向这个位置是没有形成越界访问的这种效果,仅仅指向是没有问题的!!!只有当对vp1解引用了或者说访问数组values[5]的元素了,通过vp1改数组values后面空间的数据了,那确实是非法访问了🌳

关于vp1和vp2指针问题:

实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。

🌐 标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许
指向第一个元素之前的那个内存位置的指针 进行比较。

二.指针和数组

二者区别:

指针就是指针,不是数组

数组就是数组,也不是指针

如何求大小:

指针的大小:4/8个字节,指针是存放地址的,地址的存放需要多大空间,指针变量的大小就是多少

数组的大小:取决数组的元素个数和每个元素的类型

 我们看一个例子:

#include <stdio.h>
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,0};
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    return 0;
}

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

可见数组名和数组首元素的地址是一样的。
结论: 数组名表示的是数组首元素的地址 。(2种情况除外:sizeof(数组名)+&数组名)
那么这样写代码是可行的:
int arr [ 10 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 };
int * p = arr ; //p 存放的是数组首元素的地址
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。

☑️​​​​​​​☑️​​​​​​​☑️​​​​​​​重点:

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
	int* p = arr; //指针存放数组首元素的地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i);
	}
	return 0;
}
运行结果:
C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

 💾画图笔记: 

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

循环部分的代码也可以写成:

for (i = 0; i < sz; i++)
    {
        printf("%d ", i[arr]);
        //i[arr] -- *(i+arr)
        //arr[i] -- *(arr+i)
    }

💥注意的点:

三者等价:*(arr+i)-->*(p+i)-->arr[i]

不管是写成i[arr]还是arr[i],编译器都会转换成*(arr+i)或者*(i+arr)

所以 p+i 其实计算的是数组 arr 下标为i的地址。

那我们就可以直接通过指针来访问数组。

如下:

1.指针和数组间的联系:

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	//存放
	for (i = 0; i < 10; i++)
	{
		*p = i + 1;
		p++;
	}
	
	//打印
	p = arr;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

存放的另一种写法:

for(i=0;i<10;i++)

{
     *(p+i)=i+1;

}

图解: 

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

上述图解和代码证明了: 

1.指针可以指向数组元素的

2.因为指针可以运算,所以借助于指针可以访问数组

2.用指针访问二维数组

int main()
{
	int arr[3][5];
	return 0;
}

等价的写法: 🚗

arr[i][j]  --> (*(arr+i))[j] -->*(*(arr+i)+j)

三.二级指针✅

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
答:二级指针
#include<stdio.h>
int main()
{
	int a = 10;//a是要在内存中申请4个字节的空间的
	//一级指针
	int* pa = &a;//0x0012ff40,pa是变量,用来存放地址,也得向内存申请,申请4/8
	//二级指针
	int** ppa = &pa;//0x0012ff48
	//三级指针
	int*** pppa = &ppa;
	printf("%d\n", **ppa);


	return 0;

}

✅​​​​​​​✅注意:最右边的*间隔分开只是为了更好解释它是一个什么样的指针,空格加不加无所谓的

一级指针:

int* pa = &a;  -->     *表明pa是指针,而int表明pa指向的对象a的类型是int

二级指针:是用来存放一级指针变量的地址

int* * ppa = &pa  --> *告诉我们ppa是指针,而int*表明ppa指向的对象pa的类型是int*

如此类推....

可以打开内存监视窗口看一下情况,各个变量的地址和生成的对应指针存放的地址是一样的 

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组画图: 

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

🅿️对于二级指针的运算有:

  • *ppa 通过对ppa中的地址进行解引用,这样找到的是 pa ,*ppa 其实访问的就是 pa .
int b = 20 ;
* ppa = & b ; // 等价于 pa = &b;
  • **ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .
** ppa = 30 ;
// 等价于 *pa = 30;
// 等价于 a = 30;

 还有一点:其实在开发的过程中三级指针很少用。

四.指针数组

指针数组是指针还是数组? 答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组。
int arr1 [ 5 ];
char arr2 [ 6 ];

 🚩1.存放整型指针的数组

#include<stdio.h>
int main()
{
	int* p;

	int a = 10;
	int b = 20;
	int c = 30;

	//指针数组--存放指针的数组
	int* arr[] = { &a,&b,&c };//
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%d ", *(arr[i]));
	}

	char* arr2[5];
	float* arr3[5];
	return 0;

}

执行:

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

▶️关于这里的知识点总结: 

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

 除此之外还有:
    char* arr2[5];//存放字符指针数组
    float* arr3[5];//存放浮点型指针的数组

...等等数组

2.二级指针数组的应用

int main()
{
    char* arr[5];//{char* char* char* char* char*}
    char** p = arr;//&arr[0] - char**

    return 0;
}

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组

arr表示首元素的地址也就是&arr[0],我本以为它的类型在监视中是char**,结果是char*[5] -- 上图可知。

反思得:

其实首元素的地址:&arr[0]类型确实是char**,监视的时候是表示的是一个数组,监视的是数组类型而不是数组首元素地址的类型

原因:

监视窗口有自己的规则,这个不必深究

⁉️通过整型指针存放三个一维数组

#include<stdio.h>
int main()
{     //
	int arr1[] = { 1,2,3,4,5 };//数组arr1内部的元素是连续的,但是arr1,arr2,arr3三者不一定连续
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	int* ptr[] = { arr1,arr2,arr3};

	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", ptr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

注意:数组arr1的内部元素是连续的,但是arr1,arr2,arr3三者不一定连续 

执行结果: 

C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组文章来源地址https://www.toymoban.com/news/detail-411007.html

本章完。欢迎大佬补充

到了这里,关于C初阶--指针初阶(下):指针运算+指针和数组+二级指针+指针数组的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LeetCode 2401.最长优雅子数组 ----双指针+位运算

    数据范围1e5 考虑nlog 或者n的解法,考虑双指针 因为这里要求的是一段连续的数组 想起我们的最长不重复连续子序列 然后结合一下位运算就好了 是一道双指针不错的题目

    2024年02月06日
    浏览(29)
  • C# 使用SIMD向量类型加速浮点数组求和运算(4):用引用代替指针, 摆脱unsafe关键字,兼谈Unsafe类的使用

    作者: zyl910 目录 一、引言 二、办法说明 2.1 历史 2.2 局部引用变量与引用所指的值(类似指针的 地址运算符 、间接运算符 * ) 2.3 重新分配局部引用变量(类似指针直接赋值) 2.4 引用地址调整(类似指针加减法) 2.5 引用地址比较(类似指针比较) 2.6 重新解释(类似C++的

    2024年02月15日
    浏览(32)
  • 当函数参数为一级指针,二级指针

    在讲述内容之前,先讲四点重要知识 1. 当传入参数时,函数形参会立即申请形参的内存空间,函数执行完毕后,形参的内存空间立即释放掉 。 1. 指针是存放其他变量地址的变量 。指针有自己的内存空间,内存空间存放的是其他变量的地址。 2. 指针具体指向谁,要看指针内

    2024年02月06日
    浏览(34)
  • C语言 二级指针和多级指针

    什么是二级指针? 假设: 如上,p是指针变量,寄存的是a的地址,指向的是元素a 那么,指针变量p有地址吗?指针变量p的指针指向的是? 答案是有的,指针变量也有地址,并且指针变量p也有着指向它地址的指针变量pp,也因为指针pp变量指向的地址是指针变量p的,而指针变

    2024年02月13日
    浏览(28)
  • C语言-基础语法学习-3 二级指针

    当涉及到多级指针时,C语言的灵活性和强大的指针功能可以得到充分的发挥。二级指针是指指向指针的指针,也被称为指向指针的引用。 使用二级指针可以实现以下功能: 动态内存分配:通过二级指针可以动态地分配内存块,并将其地址传递给其他函数或模块进行操作。这

    2024年02月12日
    浏览(35)
  • 【C语言15】单链表,(对于二级指针与一级指针应用的详细讲述)

    链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表 中的指针链接次序实现的 。 在上篇博客中,我们可以很清晰的看到顺序表的结构,但是链表不可以,链表的链接就是由指针指引的, 一个数据,他可能间隔着N个内存空间,但是它们却又是实实

    2024年02月15日
    浏览(31)
  • 【数据结构】双向链表 超详细 (含:何时用一级指针或二级指针;指针域的指针是否要释放)

    目录 一、简介 二. 双链表的实现 1.准备工作及其注意事项 1.1 先创建三个文件 1.2 注意事项:帮助高效记忆 1.3   关于什么时候 用 一级指针接收,什么时候用 二级指针接收? 1.4 释放节点时,要将节点地址 置为NULL,难道 节点内部的 指针域的指针 就不用置为 NULL吗?  2.双链

    2024年02月20日
    浏览(74)
  • C语言,二级指针,p,*p,**p的使用

             二级指针的使用是一个非常不易的问题,主要还是用的少了,如果经常使用到他,就会很明显的感受到其具体使用方法。 char *a[10]={\\\"as\\\",\\\"bc\\\",\\\"ssasd\\\",\\\"asd\\\"}; char **p=a;  则 p,*p,**p的含义:         在给定代码中,定义了一个字符指针数组 a ,并初始化了其中的元素

    2024年02月13日
    浏览(32)
  • 【C语言】初阶指针(指针及其类型以及野指针)

    简单不先于复杂,而是在复杂之后。 目录 1. 指针是什么? 2. 指针和指针类型  2.1  指针+-整数 2.2 指针的解引用  3. 野指针  3.1 野指针成因  3.2 如何规避野指针  指针理解的两个要点: 1. 指针是内存中最小单元的编号,也就是地址。 2. 平时口语中说的指针,通常指的是指

    2023年04月16日
    浏览(39)
  • 【C语言初阶(八)】初阶指针详解

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C语言学习分享⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习更多C语言知识   🔝🔝 我们在介绍C语言时已经给大家介绍过指针的概念以及内存地址的概念了,这里我们就不再重复说明前面的内容,对指针毫无了解的

    2024年02月09日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包