关于数组
数组必须先定义,后使用,定义时其长度必须为编译时期可以确定的常数。
只能逐个引用数组元素,不能一次引用整个数组
数组元素表示形式:数组名[下标]
数组不初始化,其元素值为随机数
对static数组元素不赋初值,系统会自动赋以0值
当全部数组元素赋初值时,可不指定数组长度
只给部分数组元素赋初值,后面的会自动填0(int,double,float,char(/0)已测试过)
static int a[5];
等价于:a[0]=0; a[1]=0; a[2]=0; a[3]=0; a[4]=0;
如 int a[5]={6,2,3};
等价于: a[0]=6; a[1]=2;a[2]=3; a[3]=0; a[4]=0;
字符数组和字符串
字符数组初始化
例 char ch[6]={“Hello”};
char ch[6]={‘ H’,’e’,’l’,’l’,’o’,’/0’};
char ch[6]=“Hello”;
char ch[]=“Hello”;
char he[5] ={'h','e','l','l','0'};
cout<< he<
字符串
没有字符串变量,用字符数组处理字符串
字符串结束标志:‘/0’
逐个字符输入/输出: %c
整个字符串输入/输出: %s
char a[]={'h','e','l','/0','l','o','/0'};
printf("%s",a);
输出:hel
scanf中%s输入时,遇空格或回车结束
例 : 若准备将字符串“This is a string.”记录下 来,错误的输入语句为: (A)
(A)scanf(“%20s”,s);
(B)for(k=0;k<17;k++)
s[k]=getchar();
(C)while((c=getchar())!=‘/n’)
s[k++]=c;
例:C++中用cin,cout
char ch1[20],ch2[20],ch3[20];
//cin>>ch1>>ch2>>ch3;
cin>>ch1;
cout<<" ch1为"<
输入:how are you 回车
输出: ch1为how ch2为烫烫烫烫烫烫烫烫烫烫烫烫烫烫how ch3为烫烫烫烫烫烫烫烫烫烫烫烫烫
烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫how
从上例可以看出:
1:字符串的输入以‘/0’、‘ ’(空格)、或者回车符 结束。输出是以‘/0’结束。
2:VC中相同类型的变量,分配地址时是从高往低分配。按地址从高到低:ch1>ch2>ch3
3:当输出的字符串结尾没有‘/0’时,就要被“烫”了,^_^
字符串连接函数strcat(安全是方法是用strcat_s函数取代)
格式:strcat(字符数组1,字符数组2)
标准库中实现:
char * strcat (char * dst, char * src)
{
char * cp = dst;
while( *cp )
++cp; /* Find end of dst */
while( *cp++ = *src++ )
; /* Copy src to end of dst */
return( dst );
}
功能:把字符数组2连到字符数组1后面
返值:返回字符数组1的首地址
说明:1)字符数组1必须足够大
2)连接前,两串均以‘/0’结束;连接后,串1的‘/0’取消,新串最后加‘/0’
3)由于不知道dst数组的长度,所以函数是不安全的。应尽量用strcat_s代替它。
字符串拷贝函数strcpy(安全是方法是用strcpy_s函数取代)
格式:strcpy(字符数组1,字符串2)
标准库中实现:
char * strcpy (char * dst, char * src)
{
char * cp = dst;
while( *cp++ = *src++ )
; /* Copy src over dst */
return( dst );
}
功能:将字符串2,拷贝到字符数组1中去
返值:返回字符数组1的首地址
说明:字符数组1必须足够大
‚拷贝时‘/0’一同拷贝
ƒ不能使用赋值语句为一个字符数组赋值
注:由于不知道dst的长度,所以函数是不安全的。应尽量用strcpy_s代替它。
字符串比较函数strcmp
格式:strcmp(字符串1,字符串2)
标准库中实现:
int strcmp (unsigned char *src , unsigned char *dst )
{
int ret = 0 ;
while( ! (ret = *src - *dst) && *dst)
++src, ++dst;
if ( ret < 0 )
ret = -1 ;
else if ( ret > 0 )
ret = 1 ;
return( ret );
}
功能:比较两个字符串
比较规则:对两串从左向右逐个字符比较(ASCII码),直到遇到不同字符或‘/0’为止
返值:返回int型整数,a. 若字符串1< 字符串2, 返回负整数
b. 若字符串1> 字符串2, 返回正整数
c. 若字符串1== 字符串2, 返回零
说明:字符串比较不能用“==”,必须用strcmp
字符串长度函数strlen
格式:strlen(字符数组)
标准库中实现:
int strlen (const char * str)
{
int length = 0;
while( *str++ )
++length;
return( length );
}
功能:计算字符串长度,从开始地址到‘/0’结束
返值:返回字符串实际长度,不包括‘/0’在内
字符串查找函数:strstr
函数名: strstr
功 能: 在字符串中查找指定字符串的第一次出现
用 法: char *strstr(char *str1, char *str2); strstr
原型:extern char *strstr(char *haystack, char *needle);
用法:#include
功能:从字符串haystack中寻找needle第一次出现的位置(不比较结束符NULL)。
说明:返回指向第一次出现needle位置的指针,如果没找到则返回NULL。
实现待找。
函数原型:
1.Copyright 1990 Software Development Systems, Inc.
char *strstr( const char *s1, const char *s2 )
{
int len2;
if ( !(len2 = strlen(s2)) )
return (char *)s1;
for ( ; *s1; ++s1 )
{
if ( *s1 == *s2 && strncmp( s1, s2, len2 )==0 )
return (char *)s1;
}
return NULL;
}
2.Copyright 1986 - 1999 IAR Systems. All rights reserved
char *strstr(const char *s1, const char *s2)
{
int n;
if (*s2)
{
while (*s1)
{
for (n=0; *(s1 + n) == *(s2 + n); n++)
{
if (!*(s2 + n + 1))
return (char *)s1;
} s1++;
}
return NULL;
}
else
return (char *)s1;
}
指针
} 在计算机内部存储器(简称内存)中,每一个字节单元,都有一个编号,称为地址。
} 在C语言中,内存单元的地址称为指针,专门用来存放地址的变量,称为指针变量(pointer variable)。
} 在不影响理解的情况中,有时对地址、指针和指针变量不区分,通称指针。
变量与地址
变量是对程序中数据存储空间的抽象
地址是内存中某个字节的编号
指针与指针变量
• 指针:一个变量的地址
• 指针变量:专门存放变量地址的变量叫指针变量
Int * i_pointer;
i_pointer-----指针变量,它的内容是地址量
*i_pointer----指针的目标变量,它的内容是数据
&i_pointer---指针变量占用内存的地址
直接访问与间接访问
直接访问:按变量地址存取变量值
间接访问:通过存放变量地址的变量去访问变量
例 i=3; -----直接访问
*i_pointer=20; -----间接访问
注:
另外,在C/C++语言程序设计中还经常使用空指针的概念。
所谓空指针就是指针变量的内容为零的状态。
注意:空指针并不是指针存储器为空或没有的概念,而是指针存放着特定的值—零值。
指针变量运算
注意:
不同数据类型的两个指针实行加减整数运算是无意义的。
px+n表示的实际位置的地址量是: (px) + sizeof(px的类型) * n
px-n表示的实际位置的地址量是: (px) - sizeof(px的类型) * n
两指针相减运算
px-py 运算的结果是两指针指向的地址位置之间相隔数据的个数。因此,两指针相减不是两指针持有的地址值相减的结果,而是按下列公式计算出的结果:
( (p) - (q) ) /类型字节长度
两指针相减的结果值不是地址量,而是一个整数值,表示两指针之间相隔数据的个数。
指针与数组
在C语言中,数组的指针是指数组在内存中的起始地址,数组元素的地址是指数组元素在内存中的起始地址。
设指针变量px的地址值等于数组指针x(即指针变量px指向数组的首元数),则:
x[i] 、*(px+i)、*(x+i) 和px[i]具有完全相同的功能:访问数组第i+1个数组元素。x[i] Û px[i] Û *(px+i) Û*(x+i)
注意:指针变量和数组在访问数组中元素时,一定条件下其使用方法具有相同的形式,因为指针变量和数组名都是地址量。但指针变量和数组的指针(或叫数组名)在本质上不同,指针变量是地址变量,而数组的指针是地址常量
例 int a[]={1,2,3,4,5,6,7,8,9,10},*p=a,i;数组元素地址的正确表示是:
(A)&(a+1) (B)a++ (C)&p (D)&p[i]
答案:D 注意a为地址常量,所以B不对。
p++,p-- (ü)
a++,a-- (´)
a+1, *(a+2) (ü)
二维数组与指针
二维数组与指针的关系示意图
int a[3][4];
(1)a是数组名,包含三个元素a[0],a[1],a[2]
(2)每个元素a[i]又是一个一维数组,包含4个元素
a[0],a的类型分别如下:
typeid(a[0]) == typeid(a[1])
typeid(a[0]) == typeid(int [4])
typeid(a) == typeid(int[3][4])
地址表示:
(1) a+1
(2) &a[1][0]
(3) a[1]
(4) *(a+1)
(5)(int *) (a+1)
地址表示
(1) &a[1][2]
(2) a[1]+2
(3) *(a+1)+2
二维数组元素表示形式:
(1)a[1][2]
(2)*(a[1]+2)
(3)*(*(a+1)+2)
例:
int a[3][4] = {0,1,2,3,10,11,12,13,20,21,22,23};
cout<<"数组a 的地址"<
<<" 该地址的整数值为:"<<*((int *)a)<
cout<<"a+1 的值为"<
<<" 该地址的整数值为:"<<*((int *)(a+1))<
cout<<"a[0] 的地址"<<&a[0]<<" 该地址的值为:"<<*(&a[0])
<<" 该地址的整数值为:"<<*((int *)&a[0])<
cout<<"&a[0]+1 的值为"<<&a[0] + 1<<" 该地址的值为:"<<*(&a[0] + 1)
<<" 该地址的整数值为:"<<*((int *)(&a[0] + 1))<
cout<<"&a[0][0]+1的值为"<<&a[0][0] + 1<<" 该地址的值为:"<<*(&a[0][0] + 1)
<<" 该地址的整数值为:"<<*((int *)(&a[0][0] + 1))<
cout<<"a 的地址"<
cout<<"a[0][0]的地址"<<&a[0][0]<<"该地址的值为:"<
cout<<"a[0][1]的地址"<<&a[0][1]<<"该地址的值为:"<
cout<
cout<<"地址a+1为"<
cout<<"地址&a[1][0]为"<<&a[1][0]<<"该地址的值为:"<<*(&a[1][0])<
cout<<"地址a[1]为"<
cout<<"地址*(a+1)为"<<*(a+1)<<"该地址的值为:"<<*(*(a+1))<
cout<<"地址(int *) (a+1)为"<<(int *) (a+1)<<"该地址的值为:"<<*((int *) (a+1))<
cout<
cout<<"地址&a[1][2]为"<<&a[1][2]<<"该地址的值为:"<<*(&a[1][2])<
cout<<"地址a[1]+2为"<
cout<<"地址*(a+1)+2为"<<*(a+1)+2<<"该地址的值为:"<<*(*(a+1)+2)<
cout<<"地址&a[0][0]+1*4+2为"<<&a[0][0]+1*4+2<<"该地址的值为:"<<*(&a[0][0]+1*4+2)<
cout<
cout<<"数组元素a[1][2]的值为"<
cout<<"数组元素*(a[1]+2)的值为"<<*(a[1]+2)<
cout<<"数组元素*(*(a+1)+2)的值为"<<*(*(a+1)+2)<
cout<<"数组元素*(&a[0][0]+1*4+2)的值为"<<*(&a[0][0]+1*4+2)<
输出:
数组a 的地址0025FB1C 该地址的值为:0025FB1C 该地址的整数值为:0
a+1 的值为0025FB2C 该地址的值为:0025FB2C 该地址的整数值为:10
a[0] 的地址0025FB1C 该地址的值为:0025FB1C 该地址的整数值为:0
&a[0]+1 的值为0025FB2C 该地址的值为:0025FB2C 该地址的整数值为:10
&a[0][0]+1的值为0025FB20 该地址的值为:1 该地址的整数值为:1
a 的地址0025FB1C该地址的整数值为:0
a[0][0]的地址0025FB1C该地址的值为:0
a[0][1]的地址0025FB20该地址的值为:1
地址a+1为0025FB2C该地址的值为:0025FB2C
地址&a[1][0]为0025FB2C该地址的值为:10
地址a[1]为0025FB2C该地址的值为:10
地址*(a+1)为0025FB2C该地址的值为:10
地址(int *) (a+1)为0025FB2C该地址的值为:10
地址&a[1][2]为0025FB34该地址的值为:12
地址a[1]+2为0025FB34该地址的值为:12
地址*(a+1)+2为0025FB34该地址的值为:12
地址&a[0][0]+1*4+2为0025FB34该地址的值为:12
数组元素a[1][2]的值为12
数组元素*(a[1]+2)的值为12
数组元素*(*(a+1)+2)的值为12
数组元素*(&a[0][0]+1*4+2)的值为12
结论:记住一个公式:x[i] Û *(x+i) 或者 &x[i] Û x+i就可以解决此类问题
指针与字符串
字符指针与字符串
C语言通过使用char数据类型的数组来处理字符串。
在字符数组中,每个数组元素都是char数据类型的变量。通常,我们把char数据类型的指针变量称为字符指针变量。字符指针变量与字符数组有着密切关系,它也被用来处理字符串。
在程序中,初始化字符指针是把内存中字符串的首地址赋予指针,并不是把该字符串复制到指针中。 另外,向字符指针赋给一个字符串常量时,指针应该指向一个静态存储空间。
在C编程中,当一个字符指针初始化为指向一个字符串常量时,不能对字符指针变量的目标赋值。
指针数组
所谓指针数组是指由若干个具有相同存储类型和数据类型的指针变量构成的集合。
指针变量数组的一般说明形式:
<存储类型> <数据类型> *<指针变量数组名>[<大小>];
指针数组名就表示该指针数组的存储首地址,即指针数组名为数组的指针。
若说明一个指针数组:
double *pa[2] ;
把一维数组a[0]和a[1]的首地址分别赋予指针变量数组的数组元数pa[0]和pa[1]:
pa[0]=a[0] ; // 等价pa[0] = &a[0][0];
pa[1]=a[1]; // 等价pa[1] = &a[1][0];
则pa[0]和pa[1]两个指针分别指向了两个一维数组a[0]和a[1]。这时我们可以通过两个指针pa[0]和pa[1]对二维数组中的数据进行处理。
指针数组赋值与初始化
赋值:
main()
{ int b[2][3],*pb[2];
pb[0]=b[0];
pb[1]=b[1];
……..
}
初始化:
main()
{ int b[2][3],*pb[ ]={b[0],b[1]};
……..
}
多级指针
在C语言中,一维数组的数据可以使用相应的一个指针进行处理。此概念也可以扩展到一维指针数组,即一维指针数组也可以用另外一个指针来处理。
例如,有一个一维字符指针数组ps[5],
char *ps[5]= { "Beijing city",
……
"London city" } ;
定义另一个指针变量pps,并且把指针数组的首地址赋予指针pps:
pps = ps ; 如图:
我们把一个指向指针变量的指针变量,称为多级指针变量。对于指向处理数据的指针变量称为一级指针变量,简称一级指针。而把指向一级指针变量的指针变量称为二级指针变量,简称二级指针。
二级指针变量的说明形式如下:
<存储类型> <数据类型> ** <指针名> ;
const型指针和void型指针
常量化的指针变量
const类型修饰符可以将指针变量常量化,主要有
下面三种形式。
常量化指针目标表达式(指向常量的指针)
一般说明形式如下:
const <数据类型>*<指针变量名称>[= <指针运算表达式>] ;
常量化指针目标是限制通过指针改变其目标的数值。
常量化指针变量(常指针)
一般说明形式如下:
<数据类型> *const <指针变量名称>= <指针运算表达式>;
常量化指针变量,使得<指针变量>的地址值不能修改。但可以通过 *<指针变量名称> 可以修改指针所指向变量的数值。
常量化指针变量及其目标(指向常量的常指针)
常量化指针变量及其目标表达式
一般说明形式如下:
const <数据类型> * const <指针变量名> = <指针运算表达式> ;
常量化指针变量及其目标表达式,使得既不可以修改<指针变量>的地址,也不可以通过*<指针变量名称>修改指针所指向变量的值。
void型指针
void型的指针变量是一种不确定数据类型的指针变量,它可以通过强制类型转换让该变量指向任何数据类型的变量或数组。
一般形式为:
void *<指针变量名称> ;
对于void型的指针变量,实际使用时,一般需通过强制类型转换才能使void型指针变量得到具体变量或数组地址。在没有强制类型转换之前,void型指针变量不能进行任何指针的算术运算。