c++ 指向字符串的指针_C语言-指针(基础)

内容

  1. 指针和指针变量
  2. 指针作为函数参数
  3. 指向数组的指针
  4. 指针数组
  5. 指向指针的指针
  6. 函数指针

一 指针

1.定义

内存中的一个字节(Byte)为一个存储单元。

存储单元的编号称为地址。

变量的地址是指该变量所在存储区域的第一个字节(单元)的地址。

c4aa0421f37c477ed12da6a94832a2db.png
这三个地址就称为变量a、b、c的指针

指针变量用于存放地址值。

指针变量的定义格式:类型说明符 *指针变量名;

例:int *pi ; 定义 pi 为指向 int 类型变量的指针变量

注:C++语言规定有效数据的指针不指向0单元(为非0值),如果指针变量值为0,即NULL(在ios.h中已定义),表示空指针,即不指向任何变量。

2.运算符

& 取址运算符

功能:返回变量的内存地址(升一级)

* 取值运算符

功能:访问指针指向的变量(降一级)

例:

int *p,m;
m = 200;
p = &m;
//则p等价于&m,*p等价于m

0dd7fe2e8d447a4226a5ec039640524e.png

3.指针变量的初始化

初始化格式:类型说明符 *指针变量名=初始地址值 ;

例:

char c, *p1 ;
p1=&c ;  /* 赋值语句,定义后进行 */

例:

char c ;
char *pc=&c ; /* 指针初始化,定义时进行 */

注:

(1)指针变量p必须初始化或赋值获得值后才能使用*p访问。

int x,*p ;
x=0 ;
*p=x ;
//是错误的

(2)若有 int m ; int *p = &m ;等价于:int m ; int *p ; p = &m ;

4.直接访问与间接访问

直接存取方式(直接访问):在程序中体现为直接使用变量名来存取变量值

间接存取方式(间接访问):在程序中体现为通过 p 来存取变量 m 的值。

0bf0dd9eb1d89cb4cd13531daea7dd4b.png
m=5,n=m 直接存取 m,*p=5,n=*p 间接存取 m

5.指针做函数参数

(1)基本类型量做函数参数

#include <iostream>
using namespace std; 
void swap(int x,int y)
{ int t;
 t=x; x=y; y=t;
}
void main( )
{  int x=3, y=9;
 swap(x,y);
 cout<< x<< ','<< y<<endl; 
}

输出:3,9

(2)使用引用

#include <iostream>
using namespace std; 
void swap(int &x,int &y)
{ int t;
 t=x; x=y; y=t;
}
void main( )
{  int x=3, y=9;
 swap(x,y);
 cout<< x<< ','<< y<<endl; 
}

输出:9,3

(3)指针做函数参数

#include <iostream>
using namespace std; 
void swap(int *px,int *py)
{ int t;
 t=*px;*px=*py;*py=t;
 }
void main( )
{ int x=3,y=9,*p1,*p2;
 p1=&x; p2=&y;
 swap(p1,p2);
 cout<< x<< ','<< y<<endl; 
 }

等价于

#include <iostream>
using namespace std; 
void swap(int *px,int *py)
{ int t;
 t=*px;*px=*py;*py=t;
 }
void main( )
{ int x=3,y=9;
 swap(&x,&y);
 cout<< x<< ','<< y<<endl; 
 }

输出:9,3


一维数组与指针

1.一维数组与指针

数组元素在内存中连续存放,数组名是该存储区的起始地址,是地址常量。

例:

int a[10]; float b[10];
 //a 是 a[0] 元素的起始地址。
 //b 是 b[0] 元素的起始地址。

例:

//假定: b = = 1000,且两个数组连续存放,则:a = = 1040
int a[10],*p;
p=a;

(1) 第i个元素值的表示(p的初值为a) :

  • *(a+i) 数组名法
  • *(p+i) 指针法
  • a[i] 下标法
  • p[i] 下标法

(2)第i个元素地址的表示(p的初值为a) :

  • a+i 数组名法
  • p+i 指针法
  • &a[i] 下标法
  • &p[i] 下标法

注:

(1)int a[]等价于int *p。

(2)p=a;用指针变量名代替数组名,p指向a[0]。但p不能赋值a,因为a是常量,即a=p是错误的。

(3)p++跳4个字节(int)。

(4)若 p = &a[6]; 则 *p 访问a[6]。a右加[]降一级变int,左&升一级变int*。

(5)通过指针变量和数组名访问元素的重要区别:

指针变量是地址变量,其指向由所赋值确定;数组名是地址常量(指针常量),恒定指向数组的第1个元素。

2.指针运算

(1)指针±数值:p±n等价于p±n*c

(2)指针-指针:结果为两指针所指向地址间数据的个数。

例:

int *px, *py, n, a[5]; 
px=&a[1]; py=&a[4]; n=py-px;

de00d9438ea68631b0d62a6ccafccb00.png

(3)指针 比较 指针:产生的结果为 0(假)和 1(真)。

3.一维数组名做函数参数

void f( int b[ ], int n ) //形参可以写成 int *b或int b[10]或 int b[ ]
{ …
 b[i]  //或 *( b+i )
 …
}
 
void main(void)
{  int a[10], *p;
 p=a;
 f( a , 10 ); //实参可以写 a 或 p 或 &a[0]
 ……
}

三 指针和字符串

1.指针和字符串

(1)定义一个字符数组存放字符串

char str[10]="Hello!";
//str是一维字符数组名,即起始地址。

(2)定义一个字符指针并令其指向一个字符串

char *strp="Hello!" ; 
//将字符串“Hello!”的首地址赋给指针变量strp。

(3)字符数组名(str)与字符指针(strp)的区别:

char str[10], *strp;

① str --- 指针常量,不论是否对字符数组赋值,数组空间已分配,str的指向明确。

strp --- 指针变量,若不赋初值,则其指向不确定。

② 赋值: char str[10], *strp;

strcpy(str, “ABC”);

str的指向不变,改变的是存储单元的内容。

strp=“Hello!”;

将 strp 指向字符串常量“Hello!”。

strp=str;

将 strp 指向字符串数组str。

(4)使用字符串指针易犯的错误:

  • char str[10]; str=“Hello!”;
    × str是指针常量,不能给常量赋值。
  • char str[10]; str[ ]=“Hello!”;
    × 不能用赋值语句给数组整体赋值。

2.字符串指针作函数参数

例:

 int my_strlen(char *s) // 自定义函数 
 { int n ; 
 for(n=0 ;*s!='0' ;s++) n++ ; 
 return(n); 
 }
 void main( )
 { char str[ ]="Hello!" ;
 cout << *str << 't'; 
 cout << my_strlen(str) << 't';
 cout << *str << endl; 
 }

输出:H 6 H

注:形参s数值的变化不会影响主调函数中的实参, 函数调用后再次输出str数组首字符, 没有变化。

字符串拷贝函数,比较以下几个函数:

1) 

void copy_string(char to[ ], char from[ ])
 { int i=0 ;
 while(from[i]!='0'; 
 { to[i]=from[i];i++ ; }
 to[i]='0' ; }

2) 

 void copy_string(char to[ ], char from[ ])
 { int i=0 ;
 while((to[i]=from[i])!='0') i++ ; }

3) 

void copy_string(char *to, char *from)
 { while((*to=*from)!='0') 
 { to++ ; from++ ; } }

4) 

 void copy_string(char *to, char *from)
 { while((*to++ = *from++)!='0') ; }

5) 

 void copy_string(char *to, char *from)
 { while(*to++ = *from++) ; }

四 二维数组与指针

1. 二维数组与指针

(1)行指针和元素指针

例:

4ea7b1fa7455a96e0a3c46216cdede2e.png
int a[3][4];

二维数组名 a 指向 a[0],a 是行指针,a+1指向下一行, 即指向a[1]。

一维数组名a[0]指向a[0][0],a[0]是元素指针,a[0]+1指向下一元素, 即指向a[0][1]。

从元素指针的角度来看:若欲访问a[i][j],可以写成 *( a[i]+j )

从行指针的角度来看:*(a+i) ==> a[i]

所以访问元素a[i][j],也可写成 *(*(a+i)+j )

(2)二维数组中元素a[i][j]地址的表示:

  • &a[i][j]
  • a[i]+j
  • *(a+i)+j

(3)二维数组中元素值的引用方法:

  • a[i][j]
  • *(a[i]+j)
  • *(*(a+i)+j)
  • (*(a+i))[j]

2. 指向一维数组的指针变量(行指针)

例:

int (*p)[4]; int a[3][4];
//定义一个行指针p,指向一维数组,该一维数组包含4个整型数值(相当于二维数组的一行元素)。
p=a ; // p和a的类型一样,类型为 int(*)[4] 

注:

(1)不可缺少() ;

(2)数组名 a 和 p 同为行指针,但 a 是指针常量,而 p 是指针变量,其他特性完全一样。

通过行指针 p 引用数组元素的方式:

  • p[i][j]
  • *(p[i]+j)
  • *(*(p+i)+j)
  • (*(p+i))[j]

对比:

  • a[i][j]
  • *(a[i]+j)
  • *(*(a+i)+j)
  • (*(a+i))[j]

比较:

①与一维数组名等价的指针变量(指向数组元素的指针)

 int a[10], *p; // 类型是 int *
 p=a;

②与二维数组名等价的指针变量(指向一维数组的指针)

 int a[3][4];
 int (*p)[4];
 p=a; // 类型是 int (*)[4]

3.二维数组名作函数参数

例:

int total(int(*p)[4], int n)  //等价int p[3][4]或int p[ ][4]
{ int i,j, sum=0;
 for( i=0 ;i<n;i++)
 for( j=0 ;j<4;j++)
 sum += *(*(p+i)+j) ;
 return sum;
}
void main(void)
{ int a[3][4],sum,i,j ;
 for(i=0;i<3;i++)
 for(j=0; j<4; j++) cin>> *(a[i]+j); 
 sum = total( a, 3 );
 cout << sum << endl;
}

4.将二维数组看成一维数组访问

法一:通用二维数组输出函数

void print(int *p, int row, int col) 
{ int i;
 for(i=0; i<row*col; i++, p++)
 { if(i%col==0) cout<<'n';
 cout<<setw(4)<< *p;
 }
 cout<<'n';
}
void main(void)
{  int a[3][4]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
 int b[2][3]={1, 2, 3, 4, 5, 6};
 print(a[0], 3, 4);  
 print(b[0], 2, 3); 
} 

法二:

void main(void)
{ int a[3][4]={...};
 int *p,i,j;
 p=a[0];
 cin >> i >> j; 
 cout<< "a[" << i << "][" << j<< "]="<< *(p+i*4+j) << endl; 
}

注:二维数组a[N][M]。二维数组按行存放,a[i][j]的前面有i*M+j 个元素;若序号从0开始,则a[i][j]的序号是:i*M+j。

获得函数处理结果的几种方法

1、利用return语句返回值(只能返回一个值)

2、利用全局变量得到函数调用结果(安全性欠佳)

3、利用指针变量作为函数参数来取得函数调用的结果(较好,可安全地得到多个结果值,涉及参数空间的分配)

(1)普通变量指针作参数

void fun(int a, int b, int *pmax, int *pmin)
{ *pmax=(a>b)?a:b ; *pmin=(a<b)?a:b ; }
void main( )
{ 
 int a, b, max, min;
 cin>>a>>b;
 fun(a, b, &max, &min);
 cout<<"max="<< max <<endl;
cout<<"min="<< min <<endl;
} 

(2)数组名做参数

void reverse( int b[ ], int n ) //等价于 int *b, int n
{ 
 int t; 
 int *p2 = b+n-1; 
 while(b < p2)
 { t = *b; *b = *p2; *p2=t; b++; p2-- ; }
}
void main(void)
{ int a[10]={1,2,3,4,5,6,7,8,9,10}, i; 
 reverse(a, 10); 
 for(i=0; i<10; i++) cout << a[i] << 't' ;
 cout << endl ;
}

4、利用引用作为函数参数来取得函数调用的结果(较好,可安全地得到多个结果值,不涉及参数空间的分配)

void fun(int a, int b, int &ma, int &mi)
{ ma=(a>b)?a:b ; mi=(a<b)?a:b ; }
void main( )
{ 
int a, b, max, min;
 cin>> a>> b;
 fun(a, b, max, min);
 cout<<"max="<< max <<endl;
 cout<<"min="<< min <<endl;
} 

六 指针数组

1.定义

数组元素全为指针变量的数组称为指针数组

int *p[10] ; 
//数组p 的10个元素 p[0], p[1] ……p[9] 都是指向 int 型数据的指针。数组的10个元素都是 int * 类型的。 

注:int (*p)[4]中,定义了一个指向数组的指针,p是指针变量;int *p[10]中p是一个以10个指针为元素的数组的数组名,是指针常量。

2.使用指针数组处理二维数组

int a[3][3],*p[3],i ; 
for(i=0;i<3;i++) p[i]=a[i];

通过指针 p 引用数组元素的方式:

  • p[i][j]
  • *(p[i]+j)
  • *(*(p+i)+j)
  • (*(p+i))[j]

3.利用字符指针数组处理字符串

例:

char *name[]={"George", "Mary", "Susan", "Tom", "Davis"};

fac157040c076235698ebccb1c3bd392.png

将上述多个字符串排序,输出:

#include <iostream>
#include <string>
void main( )
{ 
 char *name[ ]={ "George", "Mary", "Susan", "Tom", "Davis" };
 char *ptr; 
 int i, j, k, n=5;
for(i=0; i<n-1; i++)
{ 
 k=i;
 for(j=i+1; j<n; j++)
 if( strcmp(name[k], name[j])>0 ) //字符串比较
 k=j; //记住最小字符串指针的下标
 if(k!=i)
 {
 ptr=name[i]; name[i]=name[k]; name[k]=ptr;
 //通过交换地址交换指针数组元素值
 }
}
for(i=0; i<n; i++) //输出结果
 cout << name[i] <<endl;
}

4. 指针数组作 main 函数的形参

main( )函数的参数格式:

void main(int argc, char *argv[ ])
{
 …. 
}
//argc和argv就是main函数的参数,他们是程序的“命令行参数”。
//形参argc:命令行中参数的个数。这个值一开始不确定,是看自己输入了多少个参数而确定的。
//形参argv:指针数组的各元素分别指向命令行中各字符串的首地址。

注:

(1)main函数是操作系统调用的,实参只能由操作系统给出。在操作命令状态下,实参是和执行文件的命令一起给出的。例如在DOS,UNIX,Linux等系统的操作命令状态下,在命令行中包括了命令名和需要传给main函数的参数。

(2)利用指针数组作为main函数的参数,可以向程序传送命令行参数(这些参数是字符串),这些字符串的长度事先并不知道,而且各参数字符串的长度一般并不相同,命令行参数的数目是可以任意的。


七 指向指针的指针(二级间接访问)

指向指针的变量称为指针的指针。

其定义的一般格式:类型说明符 **指针变量名

df3fac9c603fc0360f3d988f4157e1fd.png

八 指针和函数

1.函数指针的定义和说明

类型说明符 (*函数指针名)(参数类型表);

(1)一个函数被编译后生成一段二进制代码,该段代码的首地址称为函数的入口地址,即函数指针。

(2)C++将函数名的值处理成函数的入口地址,函数名即函数指针。

(3)可以定义一个指针变量,用于存放函数的入口地址,该指针称为函数指针变量。

例:

int (*fp)(int,int); //定义函数指针 fp 指向具有两个整型参数,并且返回值为整型数据的函数。
int max(int,int); //说明函数 max。
fp=max ; //将函数 max 的入口地址赋给指针变量fp,fp 和 max 都指向函数的入口,即fp 和 max 的值都是函数的入口地址。

b6ece66c3ec1d569ce0b4eb4fb83b736.png

2. 函数指针的使用

函数可以通过函数名调用,也可通过函数指针调用。

如果 fp=max,则对函数 max 的调用方式是:

 max(实参表); // 通过函数名调用
 fp(实参表); // 通过函数指针调用
 (*fp)(实参表);// 通过函数指针调用

例:

#include <iostream>
using namespace std;
void main( )
{ int max(int,int),min(int,int),sum(int,int);
 int process(int, int, int (*)(int,int));
 int a,b ;
 cout << "Enter a and b:";
 cin >> a >> b ;
 cout << "max=" << process(a,b,max) <<endl;
 cout << "min=" << process(a,b,min) <<endl;
 cout << "sum=" << process(a,b,sum) <<endl; //三次调用,传递了三个不同的函数入口地址
}
int process(int x,int y, int (*fun)(int,int))
{
 return fun(x,y); 
 }
int max(int x, int y)
{ return( x>y ? x :y ); }
int min(int x, int y)
{ return( x<y ? x :y ); }
int sum(int x, int y)
{ return( x + y ); }

3. 返回指针值的函数(指针函数)

类型说明符 *函数名(参数表){ 函数体 }

例 :

 int *f1( ); 返回 int 型指针
 float *f2( ); 返回 float 型指针
 char *f3( ); 返回 char 型指针

例:

#include <iostream.h>
char *find(char *str, char ch)
{ while(*str!='0')
 if(*str==ch) return(str);
 else str++;
 return(NULL); //若找不到,返回空指针 
}
void main( ) 
{ char s[ ]="warrior"; char *p;
 p=find(s, 'r'); if(p) cout << p<< endl;// 输出 rrior
 p=find(s, 'i'); if(p) cout << p<< endl;// 输出 ior
 p=find(s, 'b'); if(p) cout << p<< endl;// 不输出
}

九 指针小结

(1)int *p;

一般指针,可与一维数组名等价。

如有:int a[10]; p=a; 可用p[i]访问数组元素。

(2)int (*p)[M];

指向含有 M 个元素的一维数组, 可与二维数组名等价。p 是一个行指针。

如有:int a[4][M]; p=a; 可用p[i][j]访问数组元素。

2e6c4704ef5e3ba99e93f6c8fbb36459.png

(3)int *p[M];

指针数组,有M个元素,每个元素都是指针,即有M个指针。

(4)int **p;

指向指针的指针。

(5)int (*p)(int, int);

函数指针,指向参数是两个整型值,并且返回整型值的函数。

(6)int *p( ){...}

返回整型指针值的函数。

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值