C++中字符串以及数组和指针的互相使用讲解

C++字符串与指针
在C++中可以用3种方法访问一个字符串(在第5章介绍了前两种方法)。
用字符数组存放一个字符串

【例】定义一个字符数组并初始化,然后输出其中的字符串。

#include <iostream>
using namespace std;
int main( )
{
  char str[]="I love CHINA!";
  cout<<str<<endl;
  return 0;
}

运行时输出:

I love CHINA!

用字符串变量存放字符串

【例】定义一个字符串变量并初始化,然后输出其中的字符串。

#include <string>
#include <iostream>
using namespace std;
int main( )
{
  string str="I love CHINA!";
  cout<<str<<endl;
  return 0;
}

用字符指针指向一个字符串

【例】定义一个字符指针变量并初始化,然后输出它指向的字符串。

#include <iostream>
using namespace std;
int main( )
{
  char *str="I love CHINA!";
  cout<<str<<endl;
  return 0;
}

对字符串中字符的存取,可以用下标方法,也可以用指针方法。

【例】将字符串str1复制为字符串str2。

定义两个字符数组str1和str2,再设两个指针变量p1和p2,分别指向两个字符数组中的有关字符,通过改变指针变量的值使它们指向字符串中的不同的字符,以实现字符的复制。

#include <iostream>
using namespace std;
int main( )
{
  char str1[]="I love CHINA!",str2[20],*p1,*p2;
  p1=str1;p2=str2;
  for(;*p1!='\\0';p1++,p2++)
    *p2=*p1;
  *p2='\\0';
  p1=str1;p2=str2;
  cout<<"str1 is: "<<p1<<endl;
  cout<<"str2 is: "<<p2<<endl;
  return 0;
}

运行结果为:

str1 is: I love CHINA!
str2 is: I love CHINA!


这个例子用来说明怎样使用字符指针。其实,对例6.13来说,用string变量来处理是十分简单的:

  string str1=″I love CHINA!″,str2; //定义string变量
  str2=str1; //将str1复制到str2

C++数组与指针
指向数组元素的指针

一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。所谓数组元素的指针就是数组元素的地址。

  int a[10];  //定义一个整型数组a,它有10个元素
  int *p; //定义一个基类型为整型的指针变量p
  p=&a[0]; //将元素a[0]的地址赋给指针变量p,使p指向a[0]

在C++中,数组名代表数组中第一个元素(即序号为0的元素)的地址。因此,下面两个语句等价:

  p=&a[0];
  p=a;

在定义指针变量时可以给它赋初值:

  int *p=&a[0]; //p的初值为a[0]的地址

也可以写成

  int *p=a; //作用与前一行相同

可以通过指针引用数组元素。假设p已定义为一个基类型为整型的指针变量,并已将一个整型数组元素的地址赋给了它,使它指向某一个数组元素。如果有以下赋值语句:

  *p=1; //对p当前所指向的数组元素赋予数值1

如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。

如果p的初值为&a[0],则:
1) p+i和a+i就是a[i]的地址,或者说,它们指向a数组的第i个元素,见图6.12。

2) *(p+i)或*(a+i)是p+i或a+i所指向的数组元素,即a[i]。

可以看出,[]实际上是变址运算符。对a[i]的求解过程是: 先按a+i×d计算数组元素的地址,然后找出此地址所指向的单元中的值。

3) 指向数组元素的指针变量也可以带下标,如p[i]与*(p+i)等价。

根据以上叙述,引用一个数组元素,可用以下方法:
下标法,如a[i]形式;
指针法,如*(a+i)或*(p+i)。其中a是数组名,p是指向数组元素的指针变量。如果已使p的值为a,则*(p+i)就是a[i]。可以通过指向数组元素的指针找到所需的元素。使用指针法能使目标程序质量高。

【例】输出数组中的全部元素。假设有一个整型数组a,有10个元素。要输出各元素的值有3种方法:

1) 下标法。

#include <iostream>
using namespace std;
int main( )
{
  int a[10];
  int i;
  for(i=0;i<10;i++)
  cin>>a[i]; //引用数组元素a[i]
  cout<<endl;
  for(i=0;i<10;i++)
   cout<<a[i]<<" "; //引用数组元素a[i]
  cout<<endl;
  return 0;
}

运行情况如下:

9 8 7 6 5 4 3 2 1 0      (输入10个元素的值)
9 8 7 6 5 4 3 2 1 0       (输出10个元素的值)

2) 指针法。
将上面程序第7行和第10行的“a[i]”改为“*(a+i)”,运行情况与(1)相同。

3) 用指针变量指向数组元素。

#include <iostream>
using namespace std;
int main( )
{
  int a[10];
  int i,*p=a; //指针变量p指向数组a的首元素a[0]
  for(i=0;i<10;i++)
    cin>>*(p+i); //输入a[0]~a[9]共10个元素
  cout<<endl;
  for(p=a;p<(a+10);p++)
    cout<<*p<<" "; //p先后指向a[0]~a[9]
  cout<<endl;
  return 0;
}

运行情况与前相同。请仔细分析p值的变化和*p的值。

对3种方法的比较:
方法(1)和(2)的执行效率是相同的。第(3)种方法比方法(1)、(2)快。这种方法能提高执行效率。

用下标法比较直观,能直接知道是第几个元素。用地址法或指针变量的方法都不太直观,难以很快地判断出当前处理的是哪一个元素。在用指针变量指向数组元素时要注意: 指针变量p可以指向有效的数组元素,实际上也可以指向数组以后的内存单元。如果有

  int a[10], *p=a;  //指针变量p的初值为&a[0]
  cout<<*(p+10);  //要输出a[10]的值

在使用指针变量指向数组元素时,应切实保证指向数组中有效的元素。

指向数组元素的指针的运算比较灵活,务必小心谨慎。下面举几个例子。

如果先使p指向数组a的首元素(即p=a),则:
1) p++(或p+=1)。使p指向下一元素,即a[1]。如果用*p,得到下一个元素a[1]的值。

2) *p++。由于++和*同优先级,结合方向为自右而左,因此它等价于*(p++)。作用是: 先得到p指向的变量的值(即*p),然后再使p的值加1。例6.5(3)程序中最后一个for语句:

  for(p=a;p<a+10;p++)
  cout<<*p;

可以改写为

  for(p=a;p<a+10;)
  cout<<*p++;

3) *(p++)与*(++p)作用不同。前者是先取*p值,然后使p加1。后者是先使p加1,再取*p。若p的初值为a(即&a[0]),输出*(p++)得到a[0]的值,而输出*(++p)则得到a[1]的值。

4) (*p)++表示p所指向的元素值加1,即(a[0])++,如果a[0]=3,则(a[0])++的值为4。注意: 是元素值加1,而不是指针值加1。

5) 如果p当前指向a[i],则
    *(p--)    先对p进行“*”运算,得到a[i],再使p减1,p指向a[i-1]。
    *(++p)   先使p自加1,再作*运算,得到a[i+1]。
    *(--p)   先使p自减1,再作*运算,得到a[i-1]。
将++和--运算符用于指向数组元素的指针变量十分有效,可以使指针变量自动向前或向后移动,指向下一个或上一个数组元素。例如,想输出a数组100个元素,可以用以下语句:

  p=a;
  while(p<a+100)
  cout<<*p++;

  p=a;
  while(p<a+100)
  {
    cout<<*p;
    p++;
  }

在用*p++形式的运算时,很容易弄错,一定要十分小心,弄清楚先取p值还是先使p加1。
用指针变量作函数参数接收数组地址

在前面介绍过可以用数组名作函数的参数。前面已经多次强调: 数组名代表数组首元素的地址。用数组名作函数的参数,传递的是数组首元素的地址。很容易推想: 用指针变量作函数形参,同样可以接收从实参传递来的数组首元素的地址(此时,实参是数组名)。下面用指针变量作函数形参。

【例】将10个整数按由小到大的顺序排列。在例5.7程序的基础上,将形参改为指针变量。

#include <iostream>
using namespace std;
int main( )
{
  void select_sort(int *p,int n); //函数声明
  int a[10],i;
  cout<<"enter the originl array:"<<endl;
  for(i=0;i<10;i++) //输入10个数
    cin>>a[i];
  cout<<endl;
  select_sort(a,10); //函数调用,数组名作实参
  cout<<"the sorted array:"<<endl;
  for(i=0;i<10;i++) //输出10个已排好序的数
    cout<<a[i]<<" ";
  cout<<endl;
  return 0;
}
void select_sort(int *p,int n) //用指针变量作形参
{
  int i,j,k,t;
  for(i=0;i<n-1;i++)
  {
    k=i;
    for(j=i+1;j<n;j++)
      if(*(p+j)<*(p+k)) k=j; //用指针法访问数组元素
    t=*(p+k);*(p+k)=*(p+i);*(p+i)=t;
  }
}

运行情况

C++编译系统将形参数组名一律作为指针变量来处理。

实际上在函数调用时并不存在一个占有存储空间的形参数组,只有指针变量。

实参与形参的结合,有以下4种形式:
实  参                 形  参
数组名              数组名

数组名            指针变量

指针变量          数组名
指针变量        指针变量

在此基础上,还要说明一个问题: 实参数组名a代表一个固定的地址,或者说是指针型常量,因此要改变a的值是不可能的。如:

  a++; //语法错误,a是常量,不能改变

而形参数组名是指针变量,并不是一个固定的地址值。它的值是可以改变的。在函数调用开始时,它接收了实参数组首元素的地址,但在函数执行期间,它可以再被赋值。如:

f(array[], int n)
{
  cout<<array; //输出array[0]的值
  array=array+3; //指针变量array的值改变了,指向array[3]
  cout<<*arr<<endl; //输出array[3]的值
}

多维数组与指针

用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。

1) 多维数组元素的地址
设有一个二维数组a,它有3行4列。它的定义为:

  int a[3][4]={{1,3,5,7},{9,11,13,15},{17,18,21,23}};

a是一个数组名。a数组包含3行,即3个元素:a[0],a[1],a[2]。而每一元素又是一个一维数组,它包含4图6.14个元素(即4个列元素),例如,a[0]所代表的一维数组又包含4个元素: a[0][0], a[0][1], a[0][2], a[0][3]。可以认为二维数组是“数组的数组”,即数组a是由3个一维数组所组成的。

从二维数组的角度来看,a代表二维数组首元素的地址,现在的首元素不是一个整型变量,而是由4个整型元素所组成的一维数组,因此a代表的是首行的起始地址(即第0行的起始地址,&a[0]),a+1代表a[1]行的首地址,即&a[1]。

a[0],a[1],a[2]既然是一维数组名,而C++又规定了数组名代表数组首元素地址,因此a[0]代表一维数组a[0]中0列元素的地址,即&a[0][0]。a[1]的值是&a[1][0],a[2]的值是&a[2][0]。


0行1列元素的地址可以直接写为&a[0][1],也可以用指针法表示。a[0]为一维数组名,该一维数组中序号为1的元素显然可以用a[0]+1来表示。

欲得到a[0][1]的值,用地址法怎么表示呢?既然a[0]+1是a[0][1]元素的地址,那么,*(a[0]+1) 就是a[0][1]元素的值。而a[0]又是和*(a+0)无条件等价的,因此也可以用*(*(a+0)+1)表示a[0][1]元素的值。依此类推,*(a[i]+j)或*(*(a+i)+j)是a[i][j]的值。

2) 指向多维数组元素的指针变量

① 指向数组元素的指针变量
【例】输出二维数组各元素的值。这里采用的方法是用基类型为整型的指针变量先后指向各元素,逐个输出它们的值。

#include <iostream>
using namespace std;
int main( )
{
  int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
  int *p;               //p是基类型为整型的指针变量
  for(p=a[0];p<a[0]+12;p++)
    cout<<*p<<" ";
  cout<<endl;
  return 0;
}

运行结果如下:

1 3 5 7 9 11 13 15 17 19 21 23

关于指向数组元素的指针变量的几点说明:
p是指向整型数据的指针变量,在for语句中对p赋初值a[0],也可以写成“p=&a[0][0]”。
循环结束的条件是“p<a[0]+12”,只要满足p<a[0]+12,就继续执行循环体。
执行“cout<<*p;”输出p当前所指的列元素的值,然后执行p++,使p指向下一个列元素。

②指向由m个元素组成的一维数组的指针变量
可以定义一个指针变量,它不是指向一个整型元素,而是指向一个包含m个元素的一维数组。这时,如果指针变量p先指向a[0](即p=&a[0]),则p+1不是指向a[0][1],而是指向a[1],p的增值以一维数组的长度为单位,见图6.17。

【例】输出二维数组任一行任一列元素的值。

#include <iostream>
using namespace std;
int main( )
{
  int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
  int (*p)[4],i,j;
  cin>>i>>j;
  p=a;
  cout<<*(*(p+i)+j)<<endl;
  return 0;
}

运行情况如下:

2 3
23

由于执行了“p=a”,使p指向a[0]。因此p+2是二维数组a中序号为2的行的起始地址(由于p是指向一维数组的指针变量,因此p加1,就指向下一个一维数组)。*(p+2)+3是a数组2行3列元素地址。*(*(p+2)+3)是a[2][3]的值。

3) 用指向数组的指针作函数参数
一维数组名可以作为函数参数传递,多维数组名也可作函数参数传递。

【例】输出二维数组各元素的值。题目与例6.7相同,但本题用一个函数实现输出,用多维数组名作函数参数。

#include <iostream>
using namespace std;
int main( )
{
  void output(int (*p)[4]); //函数声明
  int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
  output(a); //多维数组名作函数参数
  return 0;
}
void output(int (*p)[4]) //形参是指向一维数组的指针变量
{
  int i,j;
  for(i=0;i<3;i++)
    for(j=0;j<4;j++)
      cout<<*(*(p+i)+j)<<" ";
  cout<<endl;
}

运行情况如下:

1 3 5 7 9 11 13 15 17 19 21 23
(0)

相关推荐

  • C++中输出十六进制形式的字符串

    前言 在进行 i18n 相关的开发时,经常遇到字符编码转换的错误.这时如果能把相关字符串用十六进制的形式打印出来,例如,"abc" 输出成 "\\x61\\x62\\x63" 这对于 i18n 的除错来说是很有帮助的.Python 里面,只需要使用 repr() 函数就行了.可在 C++ 中如何做到这点呢? 下面是用 ostream 的格式化功能的一个简单的实现: std::string get_raw_string(std::string const& s

  • C++ 字符串去重排序实例代码

     C++ 字符串去重排序实例代码 入一个字符串,去掉重复出现的字符,并把剩余的字符串排序输出. 实现代码: #include <iostream> #include <string> using namespace std; void sort(string s) { char tmp[100]; int len=s.size(); int count=0,i,j; for (i=0;i<len;i++) { for (j=i+1;j<len;j++) { if (s[

  • c++中数字与字符串之间的转换方法(推荐)

    1.字符串数字之间的转换 (1)string --> char * string str("OK"); char * p = str.c_str(); (2)char * -->string char *p = "OK"; string str(p); (3)char * -->CString char *p ="OK"; CString m_Str(p); //或者 CString m_Str; m_Str.Format(&q

  • C++中带空格字符串的输入问题解决

    前言 字符串一直是一个重点加难点,很多笔试面试都会涉及,带空格的字符串更是十分常见,现在对字符串的输入问题进行一下总结. C++用cin输入的时候会忽略空格以后的字符,比如 char a[100]; cin>>a; C++用cin输入的时候会忽略空格以后的字符,输入"hello world"输出的是"hello": 如果用循环输入 for(int i=0;i<100;i++) { cin>>a[i]; } 这样输入100个数吗?或者定义

  • 深入解析C++中的字符数组和处理字符串的方法

    C++字符数组 用来存放字符数据的数组是字符数组,字符数组中的一个元素存放一个字符.字符数组具有数组的共同属性.由于字符串应用广泛,C和C++专门为它提供了许多方便的用法和函数. 字符数组的定义和初始化 定义字符数组的方法与前面介绍的类似.例如: char c[10]; c[0]=′I′;c[1]=′ ′;c[2]=′a′;c[3]=′m′;c[4]=′ ′;c[5]=′h′;c[6]=′a′;c[7]=′p′;c[8]=′p′;c[9]=′y′; 上面定义了c为字符数组,包含10个元素.在赋值

  • C++字符数组的输入输出和字符串结束标志使用讲解

    C++字符数组的输入输出 字符数组的输入输出可以有两种方法: 1) 逐个字符输入输出. 2) 将整个字符串一次输入或输出.例如有以下程序段: char str[20]; cin>>str; //用字符数组名输入字符串 cout<<str; //用字符数组名输出字符串 在运行时输入一个字符串,如: China 在内存中,数组str的状态如图5.9所示,在5个字符的后面自动加了一个结束符′\0′. 输出时,逐个输出字符直到遇结束符′\0′,就停止输出.输出结果为: China 如前所述

  • C++实现从输入中读取字符串

    你可以用这种方式读取一个单独的以空格结束的词: #include<iostream> #include<string> using namespace std; int main(){ cout << "Please enter a word:\n"; string s; cin>>s; cout << "You entered " << s << '\n'; } 注意,这里没有显式

  • C++中字符串以及数组和指针的互相使用讲解

    C++字符串与指针 在C++中可以用3种方法访问一个字符串(在第5章介绍了前两种方法). 用字符数组存放一个字符串 [例]定义一个字符数组并初始化,然后输出其中的字符串. #include <iostream> using namespace std; int main( ) { char str[]="I love CHINA!"; cout<<str<<endl; return 0; } 运行时输出: I love CHINA! 用字符串变量存放

  • 浅谈Go语言中字符串和数组

    go语言里边的字符串处理和PHP还有java 的处理是不一样的,首先申明字符串和修改字符串 复制代码 代码如下: package main import "fmt" var name string           //申明一个字符串 var emptyname string = "" //申明一个空字符串 func main() {  //申明多个字符串并且赋值  a, b, v := "hello", "word", &

  • js实现字符串和数组之间相互转换操作

    本文实例介绍了javascript中字符串和数组的相互转换方法,分享给大家供大家参考,具体内容如下 字符串和数组的相互转换操作是非常的重要的,因为在实际编码过程中会经常用到,所以这是必须要掌握的知识点,当然这个知识点并不难,知道了就永远知道了,并不是那种需要充分实践才能够掌握的东西,下面就做一下简单的介绍. 一.字符串转换为数组 此操作会用到split()函数,它能够以指定的字符作为分隔符,将字符串转换成一个数组,实例代码如下: var Str="abc-mng-zhang-mayi"

  • C语言中的数组和指针汇编代码分析实例

    今天看<程序员面试宝典>时偶然看到讲数组和指针的存取效率,闲着无聊,就自己写了段小代码,简单分析一下C语言背后的汇编,可能很多人只注重C语言,但在实际应用当中,当出现问题时,有时候还是通过分析汇编代码能够解决问题.本文只是为初学者,大牛可以飘过~ C源代码如下: 复制代码 代码如下: #include "stdafx.h" int main(int argc, char* argv[]) {        char a=1;        char c[] = "

  • 详解C语言中的函数、数组与指针

    1.函数:当程序很小的时候,我们可以使用一个main函数就能搞定,但当程序变大的时候,就超出了人的大脑承受范围,逻辑不清了,这时候就需要把一个大程序分成许多小的模块来组织,于是就出现了函数概念:   函数是C语言代码的基本组成部分,它是一个小的模块,整个程序由很多个功能独立的模块(函数)组成.这就是程序设计的基本分化方法: (1) 写一个函数的关键: 函数定义:函数的定义是这个函数的实现,函数定义中包含了函数体,函数体中的代码段决定了这个函数的功能: 函数声明:函数声明也称函数原型声明,函数的原

  • 深入理解C语言中使用频率较高的指针与数组

    目录 定义 指针与二维数组 指针数组与数组指针 数组指针的应用 操作 总结 定义 指针:C语言中某种数据类型的数据存储的内存地址,例如:指向各种整型的指针或者指向某个结构体的指针. 数组:若干个相同C语言数据类型的元素在连续内存中储存的一种形态. 数组在编译时就已经被确定下来,而指针直到运行时才能被真正的确定到底指向何方.所以数组的这些身份(内存)一旦确定下来就不能轻易的改变了,它们(内存)会伴随数组一生. 而指针则有很多的选择,在其一生他可以选择不同的生活方式,比如一个字符指针可以指向单个字符

  • PHP 中使用explode()函数切割字符串为数组的示例

    explode()函数的作用:使用一个字符串分割另一个字符串,打散为数组. 例如: 字符串 $pizza = "第1 第2 第3 第4 第5 第6"; 根据空格分割后:$pieces = explode(" ", $pizza); $pieces是分割后的数组,我们打印出来看下 <?php $pizza = "第1 第2 第3 第4 第5 第6"; $pieces = explode(" ", $pizza); fore

  • js中实现字符串和数组的相互转化详解

    最近看了一道JS的面试题,是这样描述的:利用var s1=prompt("请输入任意的字符串","")可以获取用户输入 的字符串,试编程将用户输入的字符串"反转",并且将字符串输出.         想了一下,字符串对象的方法中并没有实现反转的,但是数组中有,于是考虑了字符串和数组的相互转换问题.         JS中的内置对象中包括字符串对象(String)和数组对象(Array),这两个对象是可以通过它们对象的方法实现相互 转化的.对于St

  • 直观理解C语言中指向一位数组与二维数组的指针

    一维数组和指针: 对于一位数组和指针是很好理解的: 一维数组名: 对于这样的一维数组:int a[5];  a作为数组名就是我们数组的首地址, a是一个地址常量 . 首先说说常量和变量的关系, 对于变量来说, 用箱子去比喻再好不过了, 声明一个变量就声明一个箱子,比如我们开辟出一个苹果类型的箱子, 给这个变量赋值就是把盛放苹果的箱子中放入一个实实在在的苹果, 这就是变量的赋值.  而对于数组来说, 就是一组类型相同的箱子中,一组苹果箱子, 可以放入不同的苹果. 一维数组空间: 变量被声明后, 我

  • 浅谈javascript中字符串String与数组Array

    简单点就是string是字符(串)... 而array是数组...可以放数字啊,字符啊等一系列东东!!! 上个示例: 复制代码 代码如下: var str = "liuzhanqi"; document.write(str["length"]);//等价str.l ength  var str = string.fromcharcode(72, 101, 108, 108, 111, 33); document.write(str); //各整数作为unicode编

随机推荐