数组与指针

C语言中指针和数组详解 数组是一种用于存储相同类型数据的集合。数组中的每个元素都有一个固定的位置,并且可以通过索引访问。数据类型 数组名[数组大小];指针是一个变量,它存储另一个变量的地址。数据类型 *指针名;int *ptr;指针和数组是C语言中两个非常重要的概念。通过理解它们的定义、基本操作和相互关系,程序员可以编写出更加高效、灵活的代码。指针和数组的应用场景非常广泛,包括动态数组、函数参数、字符串处理等。在实际编程中,正确使用指针和数组可以显著提高程序的性能和可维护性。 阅读详情

目录

一、数组

二、指针

三、指针数组与数组指针

指针数组:

数组指针:

四、一维数组与指针

小例子1:写一个函数接收数组名并遍历输出数组元素

方法1:指针类型做函数形参

方法2:数组类型做函数形参

小例子2:写一个函数接收数组的地址(数组指针)并遍历输出

方法1:数组指针类型做函数形参

方法2:指针类型做函数形参

结论:写一个函数遍历一维数组问题

五、二维数组与指针

小例子1:写一个函数接收二维数组名并遍历输出数组元素

方法一:二维数组/数组指针类型做形参

方法二:一级指针做函数形参

方法三:二级指针类型做函数形参

总结:两种方法

小例子2:写一个函数接收二维数组地址并遍历输出数组元素


一、数组

C语言中的数组是存储在一块连续的内存空间之中的多个相同类型的变量。也就是说,即便是二维数组中的元素其地址也是连续的,而不是分行存储的。这里的地址连续指的是在进程的虚拟地址空间中是连续的,在实际的物理内存上不一定连续。

二、指针

指针是一种特殊的变量,其存放的是某种类型变量的地址。在32位系统中,指针变量的大小是4个字节。这是因为指针用来存放地址,而在32位的系统中,地址总线的位数也是32位,因此指针变量的大小也是32位即4个字节。

       二级指针指的是一个指针变量其存储的内容是另一个指针变量的地址,即指针的指针。

三、指针数组与数组指针

指针数组:

p本质是一个数组,不能对p解引用

int *p[5];

因为[ ]比*的优先级高,因此可以看成 int* p[5],即指针数组的本质是数组,其内部的元素是int*类型的指针,此时p是包含5个int*类型元素的指针

数组指针:

p本质是一个指针,指向一个int [5] 即包含5个int型元素的数组

int (*p)[5]

四、一维数组与指针

对于一个一维数组a[5],数组名a的值的是数组首元素的地址,也就是如下例子中a的类型是int *

int a[5] = {1, 2, 3, 4, 5};

但一维数组名的值是数组首元素的地址,仅此而已,其类型还是数组并不是指针,只不过能够自动类型转换成为指针,而对数组取地址 &a的本质则是一个数组指针

int (*)[5],即&a指向一个包含5个int类型元素的数组。但是实际上&a和a的值是相同的,因为数组的首地址就是数组首元素的地址,只不过类型不同。

小例子1:写一个函数接收数组名并遍历输出数组元素

方法1:指针类型做函数形参

以下这两种方式都是用指向首元素的指针类型来接收数组,因为数组名在极大多数时候跟指针是可以等价使用的,但需要注意的是,可以等价使用,但两者不等价。

void func(int *p, int len){
    for(int i = 0; i < len; ++i){
        cout<<*(p + i)<<endl;
    }

}

void func(int *p, int len){
    for(int i = 0; i < len; ++i){
        cout<<p[i]<<endl;
    }

}

int main(){
    
    int a[5] = {1, 2, 3, 4, 5};
    func(a, 5);
}

首先一个例子是用sizeof函数的时候,sizeof(数组名a)得到的是数组中所有元素占用的空间大小(以字节算),而sizeof(p)得到的是指针本身的大小,比如32位系统中就是4个字节。还有一个例子如下:即指针是可以改变的,而数组名是不可以改变的。

void func(int *p, int len){
     for(int i = 0; i < len; ++i){
        if(i){
             p += 1;
         }
        
        cout<<*p<<endl;
    }

 }

上边函数是正确的,下边代码段是错误的

for(int i = 0; i < 5; ++i){
        if(i){
            a += 1;
        }
        cout<<*a<<endl;
    }

所以,数组名跟指针之间真正的关系是:数组名可以退化成指针(数组类型自动类型转换成指向首元素的指针类型)。这就是数组和指针唯一的关系。

当我们将数组名作为实参传递的时候,会自动类型转换成指向首元素的指针类型,这也解释了为什么sizeof作用于数组名和指针的时候不同,以及数组名不能改变,指针可以改变,因为它们本来就是完全不同的两种类型。

方法2:数组类型做函数形参

当用int p[ ]做形参时候,跟用int * 完全一样,即一维数组类型做形参的时候会完全退化成指针类型,所以用sizeof在我的64位机器上的结果是8个字节。故用int p[]来接收指针类型自然是可以的。

即便是在做形参的时候指定数组大小,int p[5], 结果依然是和int *等价的

总结:int p[option]做函数形参与int *p完全等价

void func(int p[], int len){
    cout<<sizeof(p)<<endl;
    for(int i = 0; i < len; ++i){
        if(i){
            *p += 1;
        }
        
        cout<<*p<<endl;

}

int main(){

    int a[5] = {1, 2, 3, 4, 5};
    func(a, 5);
    
    return 0;
}

小例子2:写一个函数接收数组的地址(数组指针)并遍历输出

方法1:数组指针类型做函数形参

需要注意的是这次传递的实参是&a,其类型是int (*)[5]指向数组的指针,这个时候的参数传递不能发生退化或自动类型转换,即函数形参p必须也是int(*)[5]类型的。即p是一个数组指针。

void func(int (*p)[5], int len){
    for(int i = 0; i < len; ++i){
        
        cout<<(*p)[i]<<endl;
        cout<<*((*p) + i)<<endl;
    }

}

int main(){
    
    int a[5] = {1, 2, 3, 4, 5};
    func(&a, 5);
}

对数组指针解引用得到数组类型,因此这个时候对p解引用得到的是数组类型,即*p并没有退化成指向首元素的指针,*p的类型是 int[5] ,而不是int *,因此*p是不能改变的,像下面这样的代码编译不通过。

void func(int (*p)[5], int len){
    for(int i = 0; i < len; ++i){
        if(i){
            *p += 1;
        }
        // cout<<(*p)[i]<<endl;
        // cout<<*((*p) + i)<<endl;
    }

}

 

方法2:指针类型做函数形参

虽然数组指针类型&a没办法自动类型转换成指针类型int *,

void func(int *p, int len){
    for(int i = 0; i < len; ++i){
        cout<<*(p + i)<<endl;
}

}

int main(){
    
    int a[5] = {1, 2, 3, 4, 5};
    func((int *)&a, 5);
    
    return 0;
}

结论:写一个函数遍历一维数组问题

函数形参直接写成指针类型,即int *,这样可以传递数组名也可以传递数组指针,传递数组指针的时候只需要对实参进行强转就行了。

 

五、二维数组与指针

首要问题:二维数组的本质也是内存中一段连续的区域,二维数组名的值是二维数组0行0列即首元素的地址,但二维数组名的类型还是 int [][]。

小例子1:写一个函数接收二维数组名并遍历输出数组元素

方法一:二维数组/数组指针类型做形参

首先,如果要用二维数组做形参,则至少要指定列数,行数可以指定也可以不指定。

如同一维数组做形参会自动类型转换成一维指针,二维数组做形参时会自动转换成为数组指针。

二维数组做右值的时候,会自动转换成数组指针类型,即int a[2][3]会自动转换成

int (*a)[3]。因此用二维数组和用数组指针做形参是等价的。可以看到我们在输出值的时候用了两层解引用。其实对于数组指针来说,直接用a[i][j]也是可以的。用两层解引用的含义是:a是 int (*)[3]类型的数组指针,*a的结果是一个一维数组 int [3]类型(注意是数组而不是一级指针 int *),a + i的意思就是第i行数组,第一层解引用得到了第i行数组,其值就是该行第一个元素的首地址,首地址 + j再进行第二次解应用就得到的具体的值。当然,也可以在第一次解引用后直接用下标,即 cout<<(*(a + i))[j]<<endl;

void func(int a[][3], int row, int col){
    for(int i = 0; i < row; ++i){
        for(int j = 0; j < col; ++j){
            cout<<*(*(a + i) + j)<<endl;
        }
    }
}

void func(int (*a)[3], int row, int col){
    for(int i = 0; i < row; ++i){
        for(int j = 0; j < col; ++j){
            cout<<*(*(a + i) + j)<<endl;
        }
    }
}

int main(){
    
    int a[2][3] = {1,2,3,4,5,6};
    func(a, 2, 3);
    // func((int **)a, 5);

    return 0;
}

方法二:一级指针做函数形参

因为C语言中数组都是连续存储的,因此我们可以用首地址加偏移量的方式来遍历每一个元素。即

cout<<*(a + i * col + j)<<endl;

但是需要注意的是二维数组是没办法自动类型转换成一级指针的,因此在调用的时候需要强转一下。

void func(int *a, int row, int col){
    for(int i = 0; i < row; ++i){
        for(int j = 0; j < col; ++j){
             
            cout<<*(a + i * col + j)<<endl;
        }
    }
}

int main(){
    
    int a[2][3] = {1,2,3,4,5,6};
    func((int *)a, 2, 3);
    // func((int **)a, 5);

    return 0;
}

方法三:二级指针类型做函数形参

首先明确一点,二级指针int **与二维数组int [ ][ ]没有半毛钱关系!因此虽然可以用二级指针来接收二维数组,但最后遍历元素的时候还是相当于用了一级指针中首地址加偏移量的方式。即在func函数中虽然形参是二级指针,但是具体使用的时候还是转成了一级指针来用。

同理,二维数组也是没办法自动转成二级指针的,因此调用函数的时候需要强转。

void func(int **a, int row, int col){
    for(int i = 0; i < row; ++i){
        for(int j = 0; j < col; ++j){
            cout<<*((int *)a + i * col + j)<<endl;
        }
    }
}

int main(){
    
    int a[2][3] = {1,2,3,4,5,6};
    //func(a, 2, 3);
    func((int **)a, 5);

    return 0;
}

总结:两种方法

一种不需要强转,函数形参是数组指针,因为二维数组做右值自动退化成数组指针。

一种需要强转,函数形参可以理解为是一级指针,此时利用了数组的连续存储性质,用首地址加偏移量的方式来遍历输出。

小例子2:写一个函数接收二维数组地址并遍历输出数组元素

因为对二维数组取地址&a类型是 指向二维数组的指针,int (*a)[2][3],唉,没必要考虑那么多,一个强转成一级指针用首地址加偏移量遍历就行,即(int *)&a 。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

指针,截指针,数组指针,指针数组,指针与数组关系 换句话说,swap里的a,b和main函数的a,b是不同的(就像世界上同名的人有很多),这里的a,b也不是一个。定义:数组指针实际上是一个指针变量,指向数组的指针变量(数组的指针),指向的是整个数组。int(*p)[4]变量类型可以看成int[4],int[4]+1并不是添加一个字节而是添加整个数组的大小,4个int=4*4=16bit,所以说int[4]+1会跳过16个字节。*p单独出现,前面没有类型(如上文里的int)就是解指针,如代码里p=&a,说明p存的是a的地址,*p就可以获取a的值。 阅读详情

相关推荐

RseQC实战指南:从安装到RNA-Seq数据质控全流程解析

本文提供了一份详尽的RseQC实战指南,涵盖从安装配置到RNA-Seq数据质控的全流程。文章重点解析了RseQC作为专业质控工具的核心价值,手把手指导如何通过Conda或pip完成安装,并深入讲解了bam_stat.py、geneBody_coverage.py等关键模块的使用方法与结果解读技巧,帮助用户有效评估RNA完整性、文库构建质量及链特异性,确保下游分析的可靠性。

weixin_29200741的博客 201

指针与数组

较为的详细介绍了 指针与数组的关系

m0_60292931的博客 1万+

ComfyUI-controlnet控制出图

提供加载预处理器节点。

Bu2n的博客 5494

【C语言】数组和指针

数组和指针,十分全面!!

Qiuhan_909的博客 1万+

Chapter 4 Ripple-Based Control Technique Part I

本文介绍了DC-DC转换器的纹波控制技术,重点分析了迟滞控制、恒定开通时间控制、恒定关断时间控制等方案的工作原理及优缺点。纹波控制无需补偿网络,具有快速瞬态响应和结构简单的优势,特别适合电池供电应用。其中,恒定开通时间控制在轻载时能自动延长关断时间,实现伪定频工作;而恒定关断时间控制轻载效率较低。文章还讨论了纹波注入技术解决Boost转换器右半平面零点问题,并比较了不同控制方案在负载瞬态下的性能表现。最后指出基于纹波的控制技术在提高调节精度和降低EMI方面的改进方向。

2304_76736886的博客 1301

华为OD机试双机位C卷-统计差异值大于相似值二元组个数(C/C++/Py/Java/Js/Go)

华为OD机试(机考)双机位C卷 【统计差异值大于相似值二元组个数】,提供Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试 - 统计差异值大于相似值二元组个数

qq_45776114的博客 783

指针与数组的联系与区别【一万六千字超详解】

本文主要讲解的是指针与数组之间的联系与区别

malloc不出对象的博客 9440

由JavaScript版迷宫游戏引出Java版迷宫地图生成器

Java案例:迷宫地图生成器 一、引入问题 本期18软件1班网页脚本实训项目是完成一个JavaScript版迷宫游戏。 迷宫地图是如何生成的呢?很简单,将一个正方形区域等分为若干行与若干列,比如25行25列,这样就有625个单元格,用一个二维数组map[25][25]就可以保存625个单元格信息,map[i][j] = 1表示该单元格要绘制砖,而map[i][j] = 0表示该单元格不绘制砖。 ...

howard2005的专栏 1473

C语言—指针数组与数组指针

前言: 看到标题的小伙伴可能会有点疑惑,什么是指针数组,数组指针??傻傻分不清楚,不怕,听我慢慢道来。 正文: 要想弄清楚这两个概念,我们不妨举几个例子: 1、数组: int arr[5] = {1,2,3,4,5}; 这就是最简单的数组,数组中每个元素都是int类型,下面的图片帮助大家很容易理解。 数组可以将相同类型的数据整合到一起,你可以通过下标的方式或者指针的方式来访问,在这里不多赘述。 ...

weixin_44580000的博客 1万+

【教程4>第5章>第28节】基于帧同步+相位同步+位同步的QPSK调制解调通信系统整体性能分析

综上所述:1.SNR<10db时,整体性能下降,当SNR=0db时,系统无法正常工作。2.gardner环性能达到2.5e-5时偏可以正常工作,增加之后无法正常工作。3.当相位偏差大于pi/4的时候,对最后的性能会有一定影响。

FPGA/MATLAB学习教程/源码/项目合作开发 556

电气论文实现:前推回代在IEEE33节点中的潮流计算实现(matlab,python)

本文首先介绍了前推回代的原理。然后基于IEEE33节点算例,分别用python和matlab运用前推回代进行了潮流计算。

总裁余(余登武)博客 8608

二维数组与指针、指针数组、数组指针的用法

二维数组和指针⑴ 用指针表示二维数组元素。要用指针处理二维数组,首先要解决从存储的角度对二维数组的认识问题。我们知道,一个二维数组在计算机中存储时,是按照先行后列的顺序依次存储的,当把每一行看作一个整体,即视为一个大的数组元素时,这个存储的二维数组也就变成了一个一维数组了。而每个大数组元素对应二维数组的一行,我们就称之为行数组元素,显然每个行数组元素都是一个一维数组下面我们讨论指针和二维数组元素的...

gaosaixing的博客 5万+

使用自制的NTC测量模块测试Plecs的热仿真效果

可以测试:您完全可以用这个模型来测试热仿真。NTC 模型是连接电气域和热域的关键桥梁。实现闭环:通过这种方式,您创建了一个高度真实的正反馈闭环系统:负载增加 -> 损耗增加 -> 温度升高 -> NTC 阻值变化 -> 控制电路可能因此调整(如降低频率或电流)-> 损耗变化 -> 温度变化。应用场景:这对于设计过温保护 (OTP) 电路风扇控制系统以及分析热失控条件非常有用。单位:确保热域中使用的单位( Kelvin 或 Celsius )与您的 C-Script 模型输入期望的单位一致。

311

数组指针和指针数组

借用别人的博客https://blog.youkuaiyun.com/sum_tw/article/details/53540866作为自己的笔记 1、数组指针(指向数组的指针) (1)数组在内存中的表示 创建一个数组就是在内存里面开辟一块连续的空间,比如int a[4];就是在内存里面开辟了一个大小为4*sizeof(int)字节的内存空间。二维数组是特殊的一维数组。 先来看一段代码: void...

婉茹的博客 9311

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

指针数组、数组指针、数组的区别与联系

指针数组、数组指针、数组的区别与联系! 一:基本定义 1.指针数组 char *arr[4] = {"hello", "world", "shannxi", "xian"}; //arr就是我定义的一个指针数组,它有四个元素,每个元素是一个char *类型的指针,这些指针存放着其对应字符串的首地址。 (1)这个指针数组有......

魏波 1万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

数组指针与指针数组

数组指针(也称行指针) 定义 int (*p)[n]; ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。 如要将二维数组赋给一指针,应这样赋值: int a[3][4]; int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。  p=a;        //将该二...

PT的博客 1万+

指针数组,数组指针,存放数组指针的数组,指向存放数组指针数组的指针,函数指针,函数指针数组,指向函数指针数组的指针

数组:一组数据的集合称为数组,它所包含的每一个数据叫做数组元素,例如 int a[4]; 它定义了一个长度为4的整型数组,名字是a . 一般的定义数组可以用 :数据类型 数组名 [数组长度];来声明。当然数组中除了存储一般常见的数据类型外,也可以用来存放指针,此时的数组就叫指针数组。指针数组:指针数组的元素全为指针。它的声明方法是:数据类型 * 数组名[数组长度];例如int arr[5];

lrving_j的博客 6539

指针数组与数组指针的区别

a、指针数组:是指一个数组里面装着指针,也即指针数组是一个数组; 定义形式:int *a[10]; 如图所示: b、数组指针:是指一个指向数组的指针,它其实还是一个指针,只不过是指向数组而已; 定义形式:int (*p)[10]; 其中,由于[]的优先级高于*,所以必须添加(*p). 区分方法: 主要看后面的两个字是什么(前面是修饰作用),因此指针数组是数组,而数组指针是指针。 ...

汤姆鱼 5万+

C++笔记 指针与数组 指针数组与数组指针

指针:C语言中某种数据类型的数据存储的内存地址,例如:指向各种整型的指针或者指向某个结构体的指针。 数组:若干个相同C语言数据类型的元素在连续内存中储存的一种形态。 数组在编译时就已经被确定下来,而指针直到运行时才能被真正的确定到底指向何方。所以数组的这些身份(内存)一旦确定下来就不能轻易的改变了,它们(内存)会伴随数组一生; 而指针则有很多的选择,在其一生他可以选择不同的生活方式,比如一个字符指针可以指向单个字符同时也可代表多个字符等。 指针和数组在C语言中使用频率是很高的,在极个别情况下,数组和

weixin_40933653的博客 2431

指针与数组概念、指针数组、数组指针详解

指针与数组 指针可以与变量结合,也可以与数组结合使用。指针数组和数组指针是两个截然不同的概念,指针数组是一种数组,该数组存放的是一组变量的地址。数组指针是一个指针,表示该指针是指向数组的指针。 1.指向数组元素的指针 int a[5]={1,2,3,4,5}; int *p=a; //int *p=&amp;a[0]; 如上代码,指针变量p指向了a数组的首元素,其方法可有两种,int...

eternal_yy 3624

指针数组和数组指针

指针:指针相当于一个变量,不过它存放的是其它变量在内存中的地址。 数组:数组是用于储存多个相同类型数据的集合,且数组中的元素在内存中是连续存放的 指针数组和数组指针的区别? 指针数组(array of pointers):本质上是一个数组,只不过数组中的所有元素都是指针类型; 数组指针(a pointer to an array):本质上是一个指针,只不过该指针指向一个数组的首地址。 优先级:() > [] > * > + 指针数组 指针数组的定义 int* a[4];

倒地不起的土豆 3756

数组指针与指针数组的区别

数组指针与指针数组

笔墨随心 9245

数组指针 和 指针数组

在C语言中,指针是个神奇的东西,在window底层对指针的妙用无处不在。这里来总结数组针指的小结。在内存里面系统就是通过指针来寻找数组的每个元素的。 一、数组指针 1.一维数组: 数组指针:指向一个数组的指针。 int arr[]={1,2,3,4,5,6,7,8,9}; 这里有个整形数组 arr,这里我们知道arr是数组名,也是地址首元素的地址。 那么能不能定义一个指针来指向这个数组并调用数组里面的元素呢。 其实是可以的。那么指针的类型是什...

weixin_45423515的博客 2385

指针数组与数组指针变量

指针数组 实际是个数组,用来存储指针地址 定义: int * arr[SIZE]; 数组指针变量 用来存储数组地址的数组指针变量 定义: int intArr[5] = {....}; int (*arr)[5] = &intArr; 注意:定义数组指针变量要与实际的数组大小要一致 示例: int main() { int intArr[4] = { 1,2,3,4 }; int* pointArr[4]; //指针数组 int(*arrPoint)[4];//数组指针 arrPo

偷闲加油站 1504
上一篇: 进程间通信IPC(二)信号
下一篇: socket编程步骤
罗古洞的女婿
博客等级 码龄10年 1117粉丝 125原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值