指针---

目录

1.指针的基本概念

1.1地址和指针类型

1.1.1地址与取址运算

1.1.2指针与指针类型

1.1.3.数据在内存中的存取方式

1.2指针变量的定义、初始化和引用

1.2.1指针变量的定义和初始化

1.2.2指针变量的引用

2.指针的使用

2.1指针的运算

2.1.1指针的移动

2.2指向简单变量的指针

2.3指向指针变量的指针(二级指针)

3.指针与数组

3.1指向数组元组的指针

3.1.1使指针变量指向“数组”元素的方法

3.1.2指向数组元素的指针变量的运算

3.1.3指针与一维数组

3.1.4指针与字符串

3.1.5指针与二维数组

3.2指针数组

3.3数组指针



1.指针的基本概念

1.1地址和指针类型

1.1.1地址与取址运算

计算机将内存以字节为单位,划分成了一个一个的存储单元。为了能正确地访问存储单元,必须为每一个存储单元编号,这个编号就称为该存储单元的地址。

程序中定义的任何变量,系统都会分配确定的存储单元。如果一个变量只占用1个字节,则该字节的地址就是该变量的地址;如果一个变量要连续占用多个字节,将取第1个字节的地址为该变量的地址。在同一个编译环境下,在不同的时期,对同一个变量所赋予的存储空间也是不同的。

1.1.2指针与指针类型

1.指针类型

c语言中用专门的一种数据类型来表示地址信息,这就是指针类型。也就是说,若a为一个变量,则&a的数据类型是指向整形变量的指针,而&a的值是变量a的地址。所以,地址和指针是一个对象的两个方面,即用“指针”来指明&a的数据类型,而用“地址”作为它的值。

2.指针变量

如果把内存单元的地址用一个变量保存,则这个变量就称为指针变量。“指针变量”是存放地址的变量。严格地说,指针与指针变量是不同的,为了叙述方便,常常把指针变量就称为指针。

例如,int型变量a的值为8,系统就为a分配的内存地址是2000,变量p的地址是8000,而变量p中存放的值2000形象地称为“指针”。所以说,指针其实就是变量的地址。由于这个变量p存放的不是一般类型的数据,而是指针数据,所以称p为“指针变量”,或完整地称p是指向普通变量地指针变量。

1.1.3.数据在内存中的存取方式

1.直接通过变量名a对其进行存取

可以对变量a赋值,如语句a=8;还可以通过变量a的地址直接对变量a进行写操作,如语句scanf("%d\n",&a);。

2.通过指针变量p找到其所指的变量a,然后对所指向的变量a进行存取操作。

1.2指针变量的定义、初始化和引用

1.2.1指针变量的定义和初始化

指针变量定义的格式为:

类型说明符 *指针变量名[=初值];

例如:

int a=8,*p=&a;

定义p为指向整型变量a的指针变量,且将变量a的地址&a赋给了指针变量p,使p指向了变量a

在定义指针变量时,应注意以下几点:

1)指针变量名前必须有一个“*”号,表示定义的变量为指针类型。

2)类型说明符表示该指针变量所指向的变量的数据类型,如int、float、double、char等,也就是说指针变量取值后所指的内存单元中可以存放的数据类型。

3)指针变量在定义时允许对其赋初值。初值通常为某个变量的地址或为NULL(空地址)。

在c语言中可以用NULL表示指针变量不指向任何单元,称指针变量是空的。NULL是头文件“stdio.h”中定义的符号常量,其值为0。例如:

char *s=NULL;     /*表示字符型指针变量s不指向任何存储单元*/

在c语言中不允许把一个普通的数据赋予指针变量,因而下面的赋值语句是错误的:

int *p=2000;

1.2.2指针变量的引用

引用指针变量时常用到下面两个重要的运算符&和*。

&:取址运算符,后面能接任何类型的变量(包括指针变量),用于取其后的变量的地址。

*:指针运算符,后面只能接指针变量,用于访问指针变量所指向的变量。

1.指针的赋值运算

指针变量只有被赋值后,才能有确定的指向。未经赋值的指针变量一般情况下不能使用,否则将造成系统的混乱。

指针变量是一种特殊的变量,只能赋予指针类型的数据(即地址的数据类型为指针类型)。

1)在定义指针变量的同时对其进行初始化赋值。

2)在定义之后单独使用赋值语句给指针变量赋值,可以通过取地址运算和赋值方式将指针变量与简单变量相关联。

将一个指针变量的值赋给另一个指针变量,结果是两个指针指向同一个地址单元。

分析下面的运行结果,理解指针的赋值运算:

#include <stdio.h>
int main()
{
    int a=8,*p,*q;
    p=&a;
    printf("指针p的值为p=%x(是个地址)\n",p);
    printf("指针p所指向的变量的值为*p=%d\n",*p);
    q=p;
    printf("q=%x\n",q);
    printf("*q=%d\n",*q);
    return 0;
}

其结果为:

指针p的值为p=12ff44(是个地址)
指针p所指向的值为*p=8
q=12ff44
*q=8

当定义一个指针变量时,要明确其所指向的变量的数据类型。同时我们还要注意定义了一个指针变量后,该指针变量只能指向同一个类型的变量。

2.指针变量的引用

指针变量和普通变脸的共同点是它们都能存放数据,而且又都有自己的地址。不同点是变量中存放的是通常意义下的数据,而指针变量中存放的地址。

一旦指针变量指向了某个变量的地址,就可以引用该变量。

其引用方式为:

1)*指针变量名——代表所指变量的值。

2)指针变量名——代表所指变量的地址。

普通变量a和指针变量p的运用
&a表示a的地址,如&a=2000
p指针变量p的值,如p=&a=2000
*p表示指针变量p指向的变量,如*p=a=8
*&a相当于*(&a),如*(&a)=*p=a=8,一般不这么使用
&*p相当于&(*p),如&(*p)=&a=2000,一般不这么使用
*&p相当于*(&p),如*(&p)=2000
&p表示指针变量p的地址,如p=8000

1)运算符“&”和“*”的结合性是自右向左的。从某种意义上说,“&”和“*”是一种相反的运算,如上例的&*p等于*&p。但是,*&a不能等于&*a,这是由于“*”号后只能接指针变量,而a不是指针变量。

2)要避免在没有对指针变量赋值的情况下,就使用指针变量,这样会导致数据的不确定性。

3.变量的访问

指针变量经过初始化或赋值就会指向一个确定的变量,通过指针变量我们就可以对所指的变量进行访问,例如:

int a=8,t;
int *p=&a;

指针变量p指向变量a,*p表示访问指针变量p所指向的变量a的内容,对a又两种访问方式:

1)直接访问,如t=a;。

2)通过指针变量间接访问,如t=*p;。

2.指针的使用

2.1指针的运算

指针的运算是地址的运算,不同于其他数值型数据的运算,其运算规则比较特殊。

2.1.1指针的移动

1.指针的算数运算,通常只限于+、++、-、--,表达指针的移动

设p、q为某种类型的指针变量,n为整型变量,则p+n、p++、++p、p--、--p的运算结果仍为指针。在指针的移动过程中,可以通过移动指针来实现对不同数据单元的访问操作。对不同的指针类型,移动的单位长度不同。单位长度一般是指所指向的变量的数据类型长度。

下面是实现指针移动的3种常用表达式:

1)p=p+n;(p=p-n;)

2)p++;(p--;)

3)++p;(--p;)

其中,p是指针变量,n是一个整形数据。格式1)的作用是使指针p向前(向后)移动n个单位长度;而格式2)和格式3)的作用都是使指针p向前(向后)移动一个单位长度。

例如,假设a的地址为2000,则p的值为2000。执行语句p=p+1;后,表示指针p向前移动1个单位长度。如果整型变量a占用4个字节,则p的值变为2004,而不是2001,如果整型变量a占用2个字节,则p的值变为2002。

p的值发生了变化,表示指针p向前移到了下一个变量的存储单元,但指针所指单元的值是无法确定的,因此,如果此时在程序中在引用*p,则*p的值是未知的。

2.指针的关系运算

两个指针之间的关系运算是比较两个指针所指向的地址关系,例如:

#include <stdio.h>
int main()
{
    int a,b,*p1=&a,*p2=&b;
    printf("the result of (p1==p2) is %d\n",p1==p2);
    return 0;
}

其运算结果为:

the result of (p1==p2) is 0

若表达式p1==p2的值为1(真),表示p1,p2指向了同一存储单元。

2.2指向简单变量的指针

指针变量的值代表的就是所指变量的地址,所指变量的地址不会因为其变量值的变化而变化。

1.交换两个指针变量的指向。

指针变量指向的交换就是指针变量取值的交换,为此需要引进第3个指针变量,和普通变量值的交换类似,通过第三方即可实现:

int *p1,*p2,*p;
p=p1;
p1=p2;
p2=p;

2.交换两个指针变量指向的变量的值。

指针变量p1,p2指向具体变量后,可用*p1、*p2来表示所指变量,交换所指变量的值,就可以像交换普通变量的值一样,通过第三方变量temp来实现:

int *p1,*p2,temp;
temp=*p1;
*p1=*p2;
*p2=temp;

可以通过指针变量和普通变量分别来读写数据,但指针变量必须要有指向,改变指针变量的指向和通过指针变量来改变所指变量的值是不同的工作方式。

2.3指向指针变量的指针(二级指针)

指针变量作为一种变量,也占用内存空间的存储单元也有地址。c语言提供另外一种变量来保存指针变量的地址,这就是指向指针变量的指针变量,简称为指向指针的指针变量,或指向指针的指针。“指向指针的指针”常被称为“二级指针”,相应地,指向普通变量的指针则被称为一级指针。

二级指针变量的定义格式为:

类型说明符 **指针变量名[=初值]

定义二级变量时,应注意:

1)指针变量名前必须有两个“*”号,指向的变量的数据类型由类型说明符确定。

2)在定义的同时可以赋初值。初值必须是一级指针变量的地址,通常形式为“&一级指针名”

例如:

int a=10,*p,**q;
p=&a;
q=&p;

其中,定义了一个整形变量a,一个一级指针变量p和一个二级指针变量q。通过赋初值p=&a使p指向了a,而q=&p又使q指向了p。*q就代表p,**q代表*p,*p代表a,即*q的值为p的地址,**q即*(*q),其值等于*p(变量a的值)。

3.指针与数组

3.1指向数组元组的指针

可以定义一个指针变量,把数组名或数组的第一个元素的地址赋值给该指针变量,该指针变量就指向了该数组首元素。当一个指针指向了某个数组元素后,则对所有数组元素的访问操作,除了可以使用数组下标进行,也可以通过指针进行。

3.1.1使指针变量指向“数组”元素的方法

1.在定义指针变量的同时为其赋初值

例如:

int a[10],*p=&a[0],*q=&a[8];
或
int b[2][4],*p=&b[0][0],*q=&b[1][3];

2.在程序的执行语句部分为指针变量赋值

例如:

int a[10],*p,*q;
p=&a[0];
q=&a[8];
或
int b[2][4],*p,*q;
p=&b[0][0];
q=&b[1][3];

需要注意的是:定义指向数组元素的指针变量时,其指针类型应与数组的元素类型相同。

3.1.2指向数组元素的指针变量的运算

无论数组是一维数组还是二维数组,若指针变量p指向了某个数组元组,则都存在下面一些常见的指针引用及运算(下面以一维数组a为例,其中p已指向某数组元素)。

1)p++,表示p指向当前元素的下一个元素。

2)*p++,相当于*(p++)。

因为“*”和“++”运算符同优先级,且结合方向同为“自右至左”。

3)*(p++)与*(++p)

a.*(p++):同*p++

b.*(++p):对比*(p++),由于“++”在指针变量p前面,属于前置运算,遵循“先加后用”的使用原则。

4)(*p)++:对比*p++,这里的“++”运算作用于指针所指向的变量,即指针所指变量的值自增,表示p指向的元素值加1.

5)如果当前指向数组a的非首元素a[i],则:

a.*(p--),先取*p,再使p减1。

b.*(--p),先使p减1,再取*p。

一维数组和二维数组在内存中都是按行连续存放的。所以,当用一个指针变量指向一维或二维数组 的首元素后,利用该指针变量就可以访问数组中的任意一个元素。

3.1.3指针与一维数组

当指针p指向一维数组中某个元素a[i]后,可以用指针p访问一维数组的所有元素。

例如,有定义:

int a[5],*p;
p=a;

使指针p指向一维数组a的第一个元素a[0],则关于指针p与数组a的关系如下表:

指针p与一维数组a的关系
意义数组元素描述意义地址描述
数组元素a[0]的值a[0],*a,*pa的首地址a,&a[0],p
数组元素a[1]的值a[1],*(a+1),*(p+1),p[i]a[1]的地址a+1,&a[1],p+1
数组元素a[i]的值a[i],*(a+1),*(p+1),p[i]a[i]的地址

a+i,*a[i],p+i,

&p[i],&a[0]+1

注意:

1)p=p+1。使p指向下一个元素a[1]。

2)p=p+1。使p指向元素a[i]。

3)p和a都表示数组首地址。

4)指向数组的指针变量也可以带下标。

在实际应用中,一般是定义指向一维数组“首元素”的指针来对数组进行操作。下面通过几个典型例子进一步说明使用指针访问数组元素时应注意的问题。

1.指向数组元素的指针和指向简单变量的指针是不同的。

移动指向数组元素的指针可以引用数组中的每一个元素,而移动指向简单变量的指针却不能引用其他变量。

2.使用指针法访问数组元素时,要注意应尽量避免指针访问越界。

3.引用数组元素与指针变量的效率不同

1)使用下标法引用数组元素:引用速度慢,先计算出数组元素的地址(a+i),然后再找到它指向的存储单元,读入或写入它的值,但是比较直观。

2)用指针变量p指向数组元素:速度快,不必每次计算数组元素的地址,但不直观,与当前指针的位置有关。

例如,分别用3种方式访问数组中的所有元素,了解它们的区别:

#include <stdio.h>
int main()
{
    int i,a[5]={1,2,3,4,5},*p;
    printf("NO1:\t");                        /*下标法:数组名[下表]*/
    for(i=0;i<5;i++)
        printf("a[%d]=%d\t\t",i,a[i]);
    printf("\nNO2:\t");                      /*首地址法:*(首地址a+偏移量)*/
    for(i=0;i<5;i++)
        printf("*(a+%d)=%d\t",i,*(a+i));
    printf("\nNO3(1):\t");                   /*首地址法:*(首地址p+偏移量)*/
    for(p=a,i=0;i<5;i++)
        printf("*(p+%d)=%d\t,i,*(p+i));
    printf("\nNO3(2):\t");                   /*指针变量法:p在移动*/
    for(p=a;p<a+5;p++)
        printf("*p++=%d\t\t",*p);
    printf("\n");
    return 0;
}

其输出结果为:

NO1:    a[0]=1        a[1]=2        a[2]=3        a[3]=4        a[4]=5
NO2:    *(a+0)=1      *(a+1)=2      *(a+2)=3      *(a+3)=4      *(a+4)=5
NO3(1): *(p+0)=1      *(p+1)=2      *(p+2)=3      *(a+3)=4      *(a+4)=5
NO3(2): *p++=1        *p++=2        *p++=3        *p++=4        *p++=5   

4.p与a的区别:若指针p指向数组a首元素,两者同样表示数组a的地址,在表现形式上也可以互换,如p+i与a+i、*(p+i)与*(a+i)意义相同。但仍注意p与a的区别,它们的本质不同,p为指针变量,而a是数组名,是地址常量。自增(++)和自减(--)运算符不可以用于数组名。

1)a代表数组的首地址,是不变的。例如:

for(p=a;a<(p+6);a++)
    printf("%d",*a);        /*企图通过a++来改变a的值是不合法的*/

2)p是一个指针变量,可以指向数组中的任何元素,故也要注意指针变量的当前值。例如:

for(p=a,i=0;i<6;i++)
    printf("%d",*a);            /*注意指针变量的当前值*/

3.1.4指针与字符串

当字符串存放在数组中,其处理方法与一维数组的处理方法基本一致,可以先定义一个字符类型的指针变量,通过赋初值或赋值的方法让指针变量指向字符数组首元素,然后就可以使用这个指针变量处理单个字符或一次性地处理整个字符串。

例如:

char str[40]="Computer";
char *sp=str;

对字符型指针变量sp的初始化,和普通变量指针的初始化形式是一样的。这里sp的值就是字符串中第一个字符的地址,即字符串“Computer”中的第一个字符“C”的地址。

在用字符型指针变量sp处理字符串时,引用字符串中的某个字符,可以通过以下方式实现。

1)下标法:sp[i]。

2)首地址法:*(sp+i)。

3)指针变量法:*sp。

这里的i是正整数,注意到上面的第1)种情况,虽然sp并不是数组,可以像引用数组元素那样,用sp[i]来引用字符串中的字符,但不可以用它来改变字符串中sp[i]所代表的这个字符(sp指向的可能是字符串常量)。

例如,输入一个字符串,存储在字符数组中,用不同的方式显示出该字符串。分析:字符串是存储在一维字符数组中的字符序列,该字符序列的最后一位是'\0',当用字符指针变量指向字符串首地址时,用%s格式即可把字符串作为一个整体输出。如果用%c格式就需要移动指针变量指向不同的字符数组元素来输出,当然指针移动的表现形式是多种多样的。

程序如下:

#include <stdio.h>
int main()
{
    char str[40]="Computer";
    char *sp=str;
    int i;
    printf("通过指针输出数组元素:\n");
    printf("1.单个元素输出1:");
    for(i=0;i<40;i++)
    {
        printf("%c",sp[i]);
        if(sp[i]=='\0') break;
    }
    printf("\n");
    printf("2.单个元素输出2:");
    for(i=0;i<40;i++)
    {
        printf("%c",*(sp+i));
        if(*(sp+i=='\0')) break;
    }
    printf("\n");
    printf("3.单个元素输出3:");
    while(*sp!='\0')hi0
    {
        printf("%c",*sp);
        sp++;
    }
    printf("\n");
    sp=str;
    printf("4.整体输出:%s\n",sp);
    printf("\n");
    return 0;
}

在c语言中,字符型指针变量除了具有一般指针所具有的性质外,另外还有些不同的特性。下面主要讨论利用字符型的指针变量处理字符串常量的方法。

1)使字符型指针变量指向“字符串”常量

c语言对字符串常量处理时,是在内存中开辟一个字符数组来存放字符串常量(包括字符串结束符'\0')。程序可以定义字符型的指针变量指向字符串的首地址。

a.在定义字符指针变量的同时赋初值,例如:

char *sp="Computer";

b.语句执行部分给指针变量赋值,例如:

char *sp;
sp="Computr";

上述两种方式,都是把字符串的首地址即第一个字符“C”的地址赋给了指针变量sp,而不是把整个字符串“Computer”赋给sp。

2)指向字符串常量的指针变量的使用

a.把字符串当整体处理

这种方式通常用在字符串的输入和输出中,格式入下:

scanf("%s",指针变量),printf("%s",指针变量),gets(指针变量),puts(指针变量)。

b.处理字符串中的单个字符

若指针变量已经指向了字符串常量,则用指针变量表示的第i个字符为:

*(指针变量+1)。

3)使用字符指针变量与字符数组的区别

用字符指针变量和字符数组都可实现字符串的处理,但两者是有区别的,在使用时应注意以下几点

a.存储内容不同,输入字符串时有区别

字符数组是由若干个数组元素组成的,每个元素中放一个字符。如果定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址。因此下面的语句是可以的:

char *sp;
scanf("%s",sp);

字符指针变量本身是一个变量,可用于存放字符串的首地址。在定义指针变量时,若没有使它指向确定的内存单元,则该指针指向的内存位置是不确定的,而字符串本身是存放在一快连续的内存空间中并以'\0'作为字符串的结束。

所以对于字符指针变量,下面的语句是不宜采用的:

char *sp;
scanf("%s",sp);

实际编程中,应采用下面语句,使sp指向确定的内存后在使用。

char str[40];
char *sp=str;
scanf("%s",sp);

b.赋值方式不同

对字符指针变量,可采用下面方法赋值:

char *sp;
sp="Computer";
或
char *sp="Computer";

而对字符数组只能用字符串调用字符串复制函数strcpy(sp,"Computer")或循环对各个元素逐个赋值,不能用以下办法对字符数组赋值:

char sp[40];
sp="Computer";

c.指针变量的值是可以改变的,例如:

char *sp="Computer";
sp=sp+5;
printf("%s",sp);

而数组名虽然代表地址,但它是地址常量,其值是不变的,例如下面代码是错误的:

char sp[]="Computer";
sp=sp+5;
printf("%s",sp);

3.1.5指针与二维数组

例如,有定义:

int a[3][4],*p;

根据二维数组的特性,int a[3][4],可以看成是右3个一维数组a[0],a[1],a[2]构成的。

对于a[0],它的元素为:a[0][0],a[0][1],a[0][2],a[0][3]

对于a[1],它的元素为:a[1][0],a[1][1],a[1][2],a[1][3]

对于a[2],它的元素为:a[2][0],a[2][1],a[2][2],a[2][3]

对二维数组而言,数组名同样也代表着数组的首地址,当p指向二维数组a的首元素,p+1将指向数组第2个元素,p+2将指向数组第3个元组......,一般地,对于具有m行n列的数组而言,元素a[i][j]在内存中的存放顺序为第(i*n+j)个元素。

注意:二维数组与一维数组不同,以int a[3][4]为例,a、a[0]、&a[0][0]都代表数组的首地址,但它们之间存在着差异。

数组名a代表的是行指针,是数组指针,指向的对象具有4个元素,因而a+1代表的是下一行的首地址,所以p=a;这个语句在概念上容易混淆,应避免使用。

若有:int a[3][4],*p=a[0];,在程序中常用的数组元素及其地址描述如下图:

意义地址描述意义数组元素描述
a的首地址

a、*a、a[0]、&a[0][0]、p

a[0][0]的值

**a、*p、*a[0]、a[0][0]

a[0][1]的地址*a+1,a[0]+1,&a[0][0]+1,p+1a[0][1]的值

*(*a+1),*(p+1),a[0][1],*(a[0]+1),*(*a[0][1]+1)

a[1][0]的地址a+1a[1][0]的值

**(a+1),*a[1],a[1][0]

a[i][0]的地址a+ia[i][0]的值**(a+i),*a[i],a[i][0]
a[i][j]的地址...a[i][j]的值...

3.2指针数组

数组是由固定多个类型相同的元素组成的有序集合,每一个元素都是指针的数组,称为指针数组。

指针数组也是一种数组,对它的定义、赋初值、数组元素的引用等操作和一般数组的处理方法基本相同,只是数组中的每个元素都是“指针”,只能用来存放地址。一个指针变量如果指向了该数组的元素,它便是指向指针的指针变量,即多级指针。

指针数组的定义格式为:

类型说明符 *指针数组名[长度]={初值};

说明:

1)指针数组名前面必须有“*”号,表示数组的每个元素都是一个指针,指针类型由“类型说明符”指定。

2)“类型说明符”说明的不是指针数组元素的数据类型,而是它将要指向的变量的数据类型。

3)指针数组在定义的同时也可以初始化,但由于指针数组的每个元素都是指针变量,故存放的只能是地址数据。这里的“初值”与普通数组赋初值的格式相同,每个初值通常是“&普通变量名”、“&数组元素”或“数组名”,对应的普通变量或数组必须在前面已定义。

例如:

int a=10,b=20,c=30;
int *p[3]={&a,&b,&c};

其中定义了一个名为p的指针型数组,它共有p[0]、p[1]、p[2]3个元素,每一个元素都是指向整型变量的指针变量,这里分别指向整型变量a,b,c。p为指针数组名,p为数组元素的首地址,即p[0]的地址,p+i为p[i]的地址,*p是p[0],*(p+i)是p[i]。

指针数组的数组元素的引用方法和普通数组的数组元素的引用方法完全相同。可以利用指针数组元素来引用它所指向的普通变量或数组元素,可以对其赋值,也可以参与运算。

1)指针数组元素的引用格式:

指针数组名[下标]

2)指针数组元素所指向的普通变量或数组元素的引用格式:

*指针数组名[下标]

3)对指针数组元素进行赋值的格式:

指针数组名[下标]=地址表达式;

例,利用指向指针的指针变量、指针数组、二维字符数组处理多个字符串。分析:首先定义一个指针数组,二维字符数组可以看成是由一维数组组成的一维数组,把这个一维数组的每个元素地址赋值给指针数组的每个元素。这样当指向指针的指针变量指向指针数组后,就可以访问二维字符数组了:

#include <stdio.h>
int main()
{
    int i;
    char words[][16]={"internet","times","mathematics","geography"};
    char *pw[]={words[0],words[1],words[2],words[3]};
    char **ppw;
    ppw=pw;
    for(i=0;i<4;i++)
    printf("%-15s",*ppw++);
    printf("\n--------------------------\n");
    for(i=0;i<4;i++)
    {
        ppw=&pw[i];
        printf("%-15s",*ppw);
    }
    return 0;
}

注意:程序中的语句:ppw=pw; 的作用是将指针数组的首地址传递给指向指针的指针变量,因此,表示第i行的首地址应该用*(ppw+i)而不是ppw+i。

3.3数组指针

在本节中,特别指出指向“数组元素”的指针与指向“数组”的指针是两个不同的概念。如果指针只是指向数组的某个元素,则指针以元素为单位进行移动,该指针属于指向“数组元素”的指针;而如果指针指向的是某个数组,则指针移动是以数组为单位的,该指针便是指向“数组”的指针。

c语言提供了指向多个元素的指针,可以更方便地用指针来处理数组。指向数组地指针称为数组指针。

数组指针的定义格式为:

类型说明符 (*指针变量名)[一维数组长度][=初值];

表示定义一个指向一维数组的指针变量,指针变量指向的数组的数组元素类型由“类型说明符”说明,数组元素的个数由“一维数组长度”说明。初值通常是一维数组的首地址,形式为“&一维数组名”。例如:

int (*p)[4];           /*指向具有4个整形元素的数组*/
float (*pt)[3];        /*指向具有3个浮点型元素的数组*/

阅读下面的程序,了解指向简单变量的指针p和指向多个元素的指针t的特性及使用方法:

#include <stdio.h>
int main()
{
	int a[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
	int *p, (*t)[4], i, j;
	p = a[0];
	t = a;                            //p、t均指向数组的首地址
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 4; j++)
			printf("%d\t", *(*(t + i) + j));
		printf("\n");
	}
	printf("p=%lu,*p=%d\n", p, *p);
	printf("t=%lu,**t=%d\n", t, **t);
	printf("----------------------------\n");
	p = p + 1;
	t = t + 1;
	printf("p=%lu,*p=%d\n", p, *p);
	printf("t=%lu,**t=%d\n", t, **t);
	printf("----------------------------\n");
	p = p - 1;
	t = t - 1;
	printf("用指针p的移动来输出数组元素:\n");
	for (; p < a[0] + 12; p++)
		printf("%d ", *p);
	printf("\n利用指针t的移动输出数组元素:\n");
	for (; t < a + 3; t++)
		for (j = 0; j < 4; j++)
			printf("%d ", *(*t + j));
	printf("\n");
	return 0;
}

其结果为:

1       2       3       4
5       6       7       8
9       10      11      12
p=9435968,*p=1
t=9435968,**t=1
----------------------------
p=9435972,*p=2
t=9435984,**t=5
----------------------------
用指针p的移动来输出数组元素:
1 2 3 4 5 6 7 8 9 10 11 12
利用指针t的移动输出数组元素:
1 2 3 4 5 6 7 8 9 10 11 12

对于t而言,初始时t指向整个数组的首行地址,*t指向数组首行的首列地址,**t为第一个数组元素的值。由于t指向的是行地址(t是指向具有4个元素的指针),因此,*(t+i)是第i行第0列元素的地址,*(t+i)+j是第i行第j列元素的地址,*(*(t+i)+j)就是第i行第j列元素的值。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言中,结构体指针指向结构体对象的指针。通过使用结构体指针,可以对结构体进行动态操作和传递。例如,可以使用结构体指针来传递结构体作为函数参数,从而避免复制大量数据。结构体指针也可以用于动态分配内存,以便在程序运行时动态创建结构体对象。 使用结构体指针的方法有很多,其中一种常见的方法是将结构体指针作为函数参数传递,并在函数内部对结构体进行修改。这样可以避免复制整个结构体对象,提高了程序的效率。然而,需要注意的是,在使用结构体指针时,需要确保指针指向的内存空间是有效的,并要注意内存管理,避免内存泄漏或访问非法内存。 若想了解更多关于C语言结构体指针的使用方法,可以参考上述提供的参考资料。这些资料提供了关于C语言结构体指针的详细说明和示例代码,可以帮助您更好地理解和应用结构体指针。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C语言中函数如何返回结构体?](https://blog.csdn.net/Dontla/article/details/118543022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值