数组与指针.docx

上传人:b****6 文档编号:7806486 上传时间:2023-01-26 格式:DOCX 页数:19 大小:24.79KB
下载 相关 举报
数组与指针.docx_第1页
第1页 / 共19页
数组与指针.docx_第2页
第2页 / 共19页
数组与指针.docx_第3页
第3页 / 共19页
数组与指针.docx_第4页
第4页 / 共19页
数组与指针.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

数组与指针.docx

《数组与指针.docx》由会员分享,可在线阅读,更多相关《数组与指针.docx(19页珍藏版)》请在冰豆网上搜索。

数组与指针.docx

数组与指针

数组与指针

目录:

1、指针简介(p2-p5)

1.指针的声明

2.指针的初始化

3.指针间的相互赋值操作

4.void型指针

二、数组简介(p5-p9)

1.数组声明和初始化

2.数组的下标引用

3.常量数组

三、指针与数组(p9-p17)

1.指针与数组之间的关联

2.行指针和列指针

3.指针数组和矩阵数组的一些差异

4.动态内存申请

四、C-字符串(p17-p31)

1.字符串的输入输出

2.C串的相关操作函数

5、引用、C++串(p31)

(注:

本内容主要由笔记积累和个人经验及一些书目借鉴辅助而成,如有错误请及时提醒,由于编辑原因,程序一些字符自动转为大写,在电脑上编辑时请手动改正;另,因为时间精力原因,一些内容在文中已略去,如未提及请参考其他资料或请教同学)

 

1、指针简介

一般来说,指针是一个其值为地址的变量或是一个数据对象。

它提供了一种使用地址的符号方法,主要应用于数组的遍历。

1、指针的声明

(指向数据类型)*(指针变量名1);

需要注意的是:

如果声明多个指针变量,均需在变量名前加‘*’,否则视为一般变量,如:

int*v1,v2,*v3;

其中,v1、v3为指针变量,v2为int型变量。

2、指针的初始化

a、一般在声明的同时就可以进行初始化,如:

inta,*p=&a;(使用取地址符获取a变量的地址并赋给p)

b、如果暂时不用或不明确指向对象,可以先赋0或NULL(这是仅有的两个可以赋值给指针的常量,都是空的意思),当在需使用时再重新赋值。

c、还可以用指针给指针进行初始化:

inta,*p=a;

int*p1=p;

此时p1接受p传递过来的地址,和p同时指向a。

3、指针间的相互赋值操作

指针间的赋值涉及到指针间的兼容性问题,它不像普通变量有默认的类型转换(如char->int->double),它对类型要求更加严格。

必须同类型才能才可赋值,而且地址赋值操作必须是两者同时为非常量类型。

关于指针常量和常量指针:

它们都是通过const关键字来声明的。

常量指针,即:

指向常量的指针

常量指针的声明,如:

intarr[size]={0,1,2,3,4};

Constint*p=arr;

常量指针不允许通过该指针对其指向地址所存储的值进行修改,如:

*p=12;

这是系统不允许的。

指针常量的声明:

本身是一个常量的指针。

Int*constr=arr;

指针常量不允许对指针变量值进行修改,如:

Inta;r=&a;

是错误的。

(注意:

常量指针和指针常量在声明时必须初始化。

否则编译错误!

常量指针可以用常量指针初始化,如:

Constint*p1=p;//合法

指针常量同样可以用指针常量初始化,如:

Int*constr1=r;//合法

可以用指针常量给常量指针初始化,但反之不可以,系统会提示:

cannotconvertfrom'constint*'to'int*'。

(注:

用指针常量给常量指针初始后,可人为地通过指针常量来修改常量指针同样指向的相同区域的值)

4、void型指针

ANSI新标准增加了一种"void"指针类型,即可定义一个指针变量,

但是不指定它是指向哪一种数据类型。

char*p1;

void*p2;

p1=(char*)p2;//p2指针本来是void类型,可用这条语句对其强制转换,将其转换成char类型

(大家可以尝试更为标准的纯地址转换方式:

Reinterpret_cast(expression))

同样,可以用(void*)p1将p1的值转换成void*类型:

p2=(void*)p1;//将p1转换成void类型指针

也可以将一个函数定义成void*类型,如:

void*fun(charch1,charch2);表示该函数返回值是一个地址,它指向“空类型”,如果需要引用这个地址,根据需要对其进行转换.

比如需要将这个函数的返回值(地址)转换成字符型,可以这样:

p1=(char*)fun(charch1,charch2)

(注:

假定有两个已初始化的指针p1,p2

指针可参与的运算:

P1-p2......表示各自所指向地址间隔,在实际应用中无多大意义。

但:

p1+p2.....是不可以的,两个地址相加无任何意义。

P1=p2.......p2地址值赋给p1

还有自增自减等操作,一般用于数组遍历,以及引用成员操作等。

另:

注意取地址符&和解引用符(或间访寻址符)*的区别。

&是取地址,可理解为升级操作;*是从地址中取值,相当于降级操作,两者除声明变量时作用相反。

 

2、数组简介

是在C语言中允许定义的由同种数据类型项组合而成的数据

构造类型。

(而struct是C语言中允许定义的由多种类型数据项组合而成的数据构造类型)经声明定义后,其大小便不能改变。

1、数组声明和初始化

数据类型数组名[数组大小];

A、int型数组声明和初始化

一维数组的声明和初始化:

Inta[size]={0,1,2,3};

(long,float,double...类型的数组声明同int)

一般声明时size必须为常量,否则可能导致编译错误。

Size大于或等于元素个数。

如果初始化时未对所有元素初始化,其他几位默认为0;但若数组未初始化,元素值是随机的。

多维数组(以二维数组为例)的声明和初始化,如:

Intarr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

大括号中再用大括号来声明所属维数。

如果这样改:

Intarr[3][4]={{1,2,3},{4,5,6},{7,8,9},{10,11,12}};

系统会报错,由于大括号括起的元素有4组,定义为3组;

如果定义为:

Intarr[3][4]={{1,2,3},{4,5,6},7,8,9,10,11,12};

系统会自动把{1,2,3}和{4,5,6}归为arr[0]和arr[1]的元素,这时会发现剩下的有6个元素,仍会报错。

如果不加大括号将数据分开,系统会自动按行读取:

Intarr[3][4]={1,2,3,4,5,6,7,8,9,10};

系统会将{1,2,3,4}、{5,6,7,8}、{9,10,0,0}分别归为arr[0]、arr[1]、arr[2]的元素。

(注:

intarr[][4]={1,2,3};其中arr数组等同于arr[1][4],但不同于arr[4]={1,2,3};)

二维数组还可以这样初始:

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

系统会依照初始元素个数来分配arr的第二维空间(此中的arr[][4]等同于arr[2][4]。

但仅用于初始情况下)

依照数组按行存取的原则,以下定义便是非法的:

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

(无法确定内存空间的分配!

B、char型数组的声明和初始化

与int型数组相似,不同在于一维数组的大小要比元素个数多一,如:

Charc[6]={'h','e','l','l','o'};(末尾自动初始为

'\0');

注:

若将数组大小改为5,编译不一定会报错,但这会导致这些元素无法构成完整的字符串,在一些串操作中会导致错误结果。

有如:

charc[5]="Hello";

会发生编译错误

再如以下定义:

Charc[]={'h','e','l','l','o'};

和int型数组不同,在数组大小没有显示确认时,系统并不会在末尾自动添加一个'\0',在一些串操作中同样会导致错误结果!

或定义为:

Charc[6]={'h','e','l','l','o','\0'};

除此,字符数组有其他特殊的声明方式,如:

Charc1[]="hello";

Charc2[][6]={"hello","world"};

还可以通过ASCII码读取:

Charc3[6]={104,101,108,108,111,0};

或8进制(形如'\000')或十六进制(形如'\x00')表示。

结果与c1相同。

(注:

数组间不可以用数值表达式相互赋值,数组不可以用逻辑表达式整体做比较或做值运算)

2、数组的下标引用

数组的下标可以为整型非负常量、整型表达式、或整型变量。

借助下标引用可以访问数组元素。

(略)。

3、常量数组

常量数组的声明,如:

Constinta[4]={1,2,3,4};

Constcharc[6]={104,101,108,108,111,0};

值得注意的是,对于常量数组,必须在声明时对其初始化,而且每个元素都必须被初始,不能省略。

如:

Constcharc[6]={104,101,108,0};

将不能通过编译。

3、指针与数组

1、指针与数组之间的关联

一般来说,出现指针的同时一定会出现数组,因为指针的主要作用是实现数组的遍历,也是这个原因,在出现数组的同时常常能看到指针的身影。

用数组为指针初始化:

(略)

数组的遍历:

(略)

需要注意的是,不带下表的数组名相当于一个指针常量,是不能对它的地址值进行修改的。

2、行指针和列指针(相对于二维数组而言的)

A、先介绍一下数组指针和指针数组:

数组元素全为指针的数组称为指针数组:

Int*p[4];//*p[4]为指针数组,含四个指针元素。

//本质是数组

数组指针,即指向数组首元素的指针,如:

Int(*p)[4];//p为数组指针,指向数组首地址;

//本质是指针

B、行指针

即指向行坐标的的指针,如:

Inti,j;

inta[2][3];

Int(*p)[3]=a;//这里为数组指针。

For(i=0;i<2;i++)

For(j=0;j<3;j++)

Printf("%d",*(*(p+i)+j));

这段代码中,p为二维数组a的行指针,可见p为一个二级指针。

而这段代码实现的是数组的遍历输出。

C、列指针

Inti,j;

inta[2][3];

Int*p1=*a;(或int*p1=a[0];)

For(i=0;i<2;i++)

For(j=0;j<3;j++)

Printf("%d",*(p1+i*2+j));

这段代码功能与上相同,不同的是,p1为数组a的列指针,与行指针不同,它指向数组的列坐标,为一级指针。

由上,将代码合并:

Inti,j;

inta[2][3];

Int(*p)[3]=a;

Int*p1=*p;

For(i=0;i<2;i++)

For(j=0;j<3;j++)

Printf("%d",*(p1+i*2+j));

同样可实现数组遍历。

(注意解引用符*的作用,p将二级指针化为一级指针的值传给p1)

D、指向指针的指针

有如下代码:

Main()

{

Inti;

Char*ptr[]={"one","two","three","four"};

Char**p=ptr;//p为二级指针

For(i=0;i<4;i++)

{

Cout<<*p<

P++;

}

}

以上代码实现对指针数组内的字符串的遍历输出。

P即为指向ptr[0]的指针,ptr[0]实际上是指向字符串"one"的指针,存储"one"的地址,p即为指向指针的指针。

上述代码可以修改为:

Main()

{

Inti;

Char*ptr[]={"one","two","three","four"};

For(i=0;i<4;i++)

{

Cout<

}

}

同样可实现相同功能,至于指向指针的指针的功用这里不加叙述。

3、指针数组和矩阵数组的一些差异

这里用一个实例来简述。

有一下定义:

Charfruit[3][7]={"APPLE","PEAR","ORANGE"};

Char*fruit1[3]={"APPLE","PEAR","ORANGE"};

关于内存存储:

矩阵数组fruit存储情况如下:

A

P

P

L

E

'\0'

'\0'

P

E

A

R

'\0'

'\0'

'\0'

O

R

A

N

G

E

'\0'

共需21字节。

指针数组fruit1存储情况如下:

A

P

P

L

E

'\0'

P

E

A

R

'\0'

O

R

A

N

G

E

'\0'

共需18字节。

由此指针数组应用于字符串,可以更多的节省内存。

数组遍历:

对于指针数组,它不仅可以用像矩阵数组那样用下标引用的方式读取每个字符串,由于ptr指向"APPLE"第一个字符'A'的地址,通过间接访问的形式,也可以挨个读取字符。

4、动态内存申请

在实际程序应用中,我们会碰到这样一类情况,有时候我们

依照设计在一段时间内要一定的储存空间来储存一定数据,而这段时间以外不需要这些额外的空间,这会在程序运行中造成不必要的内存浪费,为了减少这种内存浪费,在程序中就有了动态内存申请的用武之地。

A、malloc与free

malloc函数原型:

void*malloc(unsignedsize)

(声明void*类型是为了适应其它标准类型)

malloc()函数的返回值要赋给一个相同类型的指针。

free函数原型:

voidfree(void*p)

malloc和free是C中内存分配和内存申请函数,函数原型都包含在malloc.h的头文件中,具体用法用下述代码说明:

#include

#include

intmain()

{

char*p[100];

inti=0;

for(;i<100;i++)

{p[i]=(char*)malloc(sizeof(char)*100);

//连续申请100个100字节的内存

scanf("%s",p[i]);//向p[i]地址输入字符串值

printf("%s\n",p[i]);//输出p[i]指向的字符串

}

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

free(p[i]);

//连续释放p[i]内存

return0;

}

注:

其中申请动态内存的语句可以等价替换为:

p[i]=(char*)calloc(100,sizeof(char));

B、new和delete

new和delete是C++中很重要的两个内置操作符,有比较复杂

的语法结构与应用,其语言本身已固定,无法重新定制。

在此仅对其中一种形式(newoperator)作介绍。

有如下一段代码:

#include

usingnamespacestd;

intmain()

{

char*p[100];

inti=0;

for(;i<100;i++)

{p[i]=newchar[sizeof(char)*100];//注意是方括号

cin>>p[i];

cout<

}

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

delete[]p[i];//注意释放方式的不同

return0;

}

注:

这段代码与前一段代码功能相同

使用时要注意由于释放格式的不同而造成的一些差异,如:

Deletep[i];

语句本身没有语法错误,但它仅释放p[i]指向的//第一个单位的1字节的内存(如果是int,则是4字节),而上述代码中的释放内存语句可以释放p[i]所分配到的整块内存。

另:

使用上述new来申请动态内存有两方面含义:

第一,它分配足够的内存,用来放置某类型的对象。

第二,它调用一个构造函数,为刚才分配的内存中的那个对象设定初始值。

(应用于class时)

(注:

应用于class,delete可以自动调用析构函数,而malloc和free不会有与new和delete相同的操作)

四、C-字符串

C风格字符串通常以字符数组的形式出现(也有用指针指向字符串常量的),故也涉及到很多与数组相关的操作和内容。

所以学习C风格字符串应与字符数组联系起来,由于数组和指针使用比较灵活,也给C串的使用造成一定的麻烦!

1、字符串的输入输出

以数组为存储方式的C串具有能整体输入输出的特性。

在C语言中,提供了一些用于输入输出的函数:

gets(),

puts(),scanf(),printf(),getchar(),putchar()等函数。

以上6个函数的函数原型都包含在头文件stdio.h中。

(注:

字符指针这样初始化:

Char*p=”hello”;

系统会这样处理:

先定义一个数组:

constcharstr[]=”hello”;

然后有:

char*p=str;

只是这个数组名无从得知)

A、gets()函数,puts()函数

关于gets的函数原型描述如下:

Char*gets(char*s)

它以两种方式获得输入:

1、使用一个地址把字符串赋予name(name为函数体中定义的一个数组名)

2、返回地址给一个char型的指针s,若读取失败,返回一个空地址0或NULL.(这使得s在主函数中即使未初始也不至于成为野指针!

Gets()在读取字符串时,以'\0'为结束标志,能读取包括空格在内的其他字符。

而puts()函数则是输出一个字符串,执行的正是与gets()相反的操作。

Puts()会读取被操作的字符串中的每个字符并输出,知道遇到空字符结束,期间包括空格在内的以及换行符(执行换行操作)等其他字符并输出。

B、scanf()和printf()函数

字符串输入,例:

#include

Intmain()

{

Charc[100];

Scanf("%s",c);

Charc1[20]="OK,\nitsuptoyou!

";

Printf("%s\n%s",c,c1);

Return0;

}

输入:

Itsagoodidea!

输出:

Its

OK,

Itsuptoyou!

分析:

对于scanf()函数,在读取字符串时遇到空格或空字符或换行符都会停止读入。

而printf()函数则会读取并输出所有字符,直到遇到空字符或字符串结束时结束。

注:

作为个是输入输出函数,格式命令符%作用很重要,输出字符串的格式命令为"%s"。

(对于其他格式输入输出的格式要求及相关格式命令这里不多做介绍)

C、getchar()和putchar()函数

Getchar()和putchar()函数分别在读入和输出时都是

以单个字符为操作单位的。

并且能对除空字符外的所有字符进行操作。

正是gets()和puts()函数的细化版。

D、预定义函数getline()及cin读入、cout输出

C++中对字符串操作的cin的成员函数,用于读取字符

串:

#include

Usingnamespacestd;

Intmain()

{

Charc[100];

Cin.getline(c,100,'!

');

Charc1[20]="OK,\nitsuptoyou!

";

Cout<

Return0;

}

该段程序改自本部分B讲中的示例程序,当进行相同的输入后输出:

Itsagoodidea!

OK,

Itsuptoyou!

Getline()函数有三个参数,后两个在原型中都具有默认值。

第三个参数为结束标志符,默认为'\n',本题中设置为’!

'即遇'!

'结束读入。

(虽然貌似本题这样设没多大作用)

cout对于字符串的输出:

与printf()相似,可以输出

包括换行符及空格在内的字符,直到遇到空字符结束;而cin读入时遇到空格或换行符或空时都会停止读入。

(注:

getline()函数也用在string类中,但使用方法略有不同:

Strings;

Getline(cin,s);

2、C串的相关操作函数

主要对几个较常用的函数做以下简述:

strlen(),

Strcmp()等。

注:

这类函数大多以'\0'为终止标示符。

函数名:

strlen

功能:

在串中查找指定字符串的第一次出现

用法:

intstrlen(char*str1);

程序例:

#include

#include

intmain(void)

{

char*str="BorlandInternational";

intptr=strlen(str);

printf("Thesubstringis:

%d\n",ptr);

return0;

}

注:

注意与sizeof区别,如:

Chara[]="abcdefg",b[10]="abcdefg";

Strlen(a)值为7,strlen(b)为7;而sizeof(a)为8,sizeof(b)为10;

又如:

Char*a="abcdefg",b[10]="abcdefg";

Strlen(a)值为7,strlen(b)为7;而sizeof(a)为4,sizeof(b)为10;

 

函数名:

strcpy

功能:

拷贝一个字符串到另一个

用法:

char*stpcpy(char*destin,char*source);

程序例:

#include

#include

intmain(void)

{

charstring[10];

char*str1="abcdefghi";

stpcpy(string,str1);

printf("%s\n",string);

return0;

}

函数名:

strcat

功能:

字符串拼接函数

用法:

char*strcat(char*destin,char*source);

程序例:

#include

#include

intmain(void)

{

chardestination[25];

char*blank="",*c="C++",*Borland="Borland";

strcpy(destination,Borland);

strcat(destination,blank);

strcat(destination,c);

printf("%s\n",destination);

return0;

}

函数名:

strcmp

功能:

串比较

用法:

intstrcmp(char*str1,char*str2);

逐个判断,直到遇到'\0';看Asicii码,str1>str2,返回值>0;两串相等,返回0

str1

程序例:

#include

#i

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1