C++指针和数组:字符和字符串、字符数组的关联和区别

 更新时间:2022年12月23日 17:35:38   投稿:yin  
字符串是一种重要的数据类型,但是c语言并没有显示的字符串数据类型,因为字符串以字符串常量的形式出现或者存储于字符数组中。在C++标准模板库(STL)中提供了string类,实现了对字符串的封装。

字符串的本质就是字符数组,将字符串作为字符数组来处理。字符数组和字符串都可以作为存放字符的数组,所以可以通过数组的下标访问每一个字符。字符串比较正如在C++中可以用3种方法(字符数组、字符串(类)、字符指针)访问一个字符串,比较字符串(内容)自然也有这三种基本形式。

字符串是一种重要的数据类型,但是c语言并没有显示的字符串数据类型,因为字符串以字符串常量的形式出现或者存储于字符数组中。在C++标准模板库(STL)中提供了string类,实现了对字符串的封装。但是其实现原理还是居于字符和指针,要了解这个原理,我们先看一下有关字符数组、字符和字符串之间的一些关联。

区别:字符数组的长度就是字符的总长度,而字符串会+1,是因为包含了最后的“\0”结束符。

一、字符指针、字符数组

字符指针

字符串指针变量本身是一个变量,用于存放字符串的首地址。而字符串本身是存放在以该首地址为首的一块连续的内存空间中并以 \0 作为串的结束。

char *ps="C Language";

顺序是:1.分配内存给字符指针;2.分配内存给字符串;3.将字符串首地址赋值给字符指针;

char *ps;  // ps 字符串指针,是指针,是一个变量

ps="C Language"; // ps 为字符串的首地址,利用 ps++ 可遍历字符串,字符串存储在以 ps 为开始地址的地段连续的内存空间中,并以 \0 作为字符串的结束。

这里有两点需要考虑清楚的地方:

1、*a 只是指向一个字符。

举例如下:

#include <stdio.h>
#include <stdlib.h>
 
int main(void){  
    char *a= "bcd" ;  
    printf("输出字符:%c \n", *a);  /*输出字符,使用"%c"*/
    printf("输出字符:%c \n", *(a+1) );  /*输出字符,使用"%c"*/
    printf("输出字符串:%s \n", a); /*输出字符串,使用"%s";而且a之前不能有星号"*"  */
    system("pause");  /*为了能看到输出结果*/
}

运行结果如下:

输出字符:b 
输出字符:c 
输出字符串:bcd

2、若字符串常量出现在在表达式中,代表的值为该字符串常量的第一个字符的地址。所以 hello 仅仅代表的是其地址。原声明方式相当于以下声明方式:

char *a;  
a="hello"; /*这里字符串"hello"仅仅代表其第一个字符的地址*/

字符数组

字符数组是由于若干个数组元素组成的,它可用来存放整个字符串。(即用字符数组来存放字符串)。

在 C 语言中,将字符串作为字符数组来处理。(C++中不是)

字符数组初始化的方法:

1). 可以用字符串常量来初始化字符数组:

char  str[]={"Iamhappy"};

可以省略花括号

char  str[]="Iamhappy";  # 系统自动加入 \0

注意:上述这种字符数组的整体赋值只能在字符数组初始化时使用,不能用于字符数组的赋值,字符数组的赋值只能对其元素一一赋值。

下面的赋值方法是错误的:

char str[20];
str="Iamhappy";

对字符数组的各元素逐个赋值。

char str[10]={'I','','a','m','','h','a','p','p','y'};

在 C 语言中,可以用两种方法表示和存放字符串:

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

char str[]="IloveChina";

(2)用字符指针指向一个字符串

char *str="IloveChina";

两种表示方式的字符串输出都用:printf("%s\n", str);

%s 表示输出一个字符串,给出字符指针变量名 str(对于第一种表示方法,字符数组名即是字符数组的首地址,与第二种中的指针意义是一致的),则系统先输出它所指向的一个字符数据,然后自动使 str 自动加 1,使之指向下一个字符...,如此,直到遇到字符串结束标识符 \0 。

二、字符串指针

string* str 可以赋值:

string* str = {"hello", "world"}; 
//  对比与 char *name = "wang" = {'w','a','n','g'}
//  *(str) = "hello", *(str+1) = "world"
//  *(*(str)+1) = 'e'

也就是说每个元素都是 string 类型的,跟 char* 是不一样的,不过 string* 可以用 char** 来代替:

string = char*, string* = char**

三、(字符串)指针数组

实例

#include <stdio.h>
void main()
{
    char *str[] = {"Hello", "C++", "World"}; //char (*str)[] = ...
    int i;
    for(i=0; i<3; i++)
        printf("%s\n", str[i]);
} 
// str[0]字符串"hello"的首地址,str[0]+1:字符串"hello"第二个字符'e'的地址,str[2]=str+2:第三个字符串"world"的首地址
// str[1]字符串"C++"的首地址
// str[2]字符串"world"的首地址

实例

#include <stdio.h>
#include <string.h>
int main()
{
   char *str[] = {"Hello", "C++", "World"};
   char **p;
   for(p=str; p<str+3; p++)
     puts(*p); #*p为字符串首地址,*p[0]为字符串的第一个字符地址
}

实例

#include<stdio.h>
#include<stdlib.h>
int main()
{
    char *str[3]={"Hello","C++","World"};
    printf("%s,%s,%c",str[0],str[0]+1,*(*(str+2)+1));
    system("pause");
}

结果为:

Hello,ello,o

格式:char* na[N] = {"li", "zh", "li", "zh", "li"};

char *a[]:表示a是数组,数组中的元素是指针,指向char类型,(数组里面所有的元素是连续的内存存放的) 数组名是数组第一个字节的内存地址,并且数组名a也表示指针。所以a 并不表示a地址存储的内容, 而是a地址本身。

a+1:表示 a 的第二个元素的内存地址, 所以是加 8 字节。( 因为a的元素是char 指针, 所需要的空间为8字节(64位内存地址)。 )

*(a+1):则表示a这个数组的第二个元素的内容 (是个char 类型的指针,本例表示为world字符串的地址)。

*(*(a+1)):则表示a这个数组的第二个元素的内容(char指针)所指向的内容(w字符).

char * a[10]:表示限定这个数组最多可存放10个元素(char指针), 也就是说这个数组占用10*8 = 80字节。

#w:        a+1   =>   *(a+1)  =>   *(a+1)[0]
           指针(地址)   指针内容(字符串)      字符

四、总结

char *argv:理解为字符串
char **argv:理解为字符串指针
char *argv[]:字符串指针数组

int main(int argc, char*argv[]) 这是一个典型的数组名(或者说是指针数组)做函数参数的例子,而且还是没有指定大小的形参数组。

有时为了再被调用函数中处理数组元素的需要,可以另设一个形参,传递需要处理的数组元素的个数。而且用数组名做函数实参时,不是吧数组元素的值传递给形参,而是把实参数组的首元素的地址传递给形参数组,这样两个数组久共同占有同一内存单元。 和变量作函数参数的作用不一样。

可以去看看关于数组作为函数参数和指针数组作main函数形参方面的例子。谭浩强的那本书讲的很细,对这个有详细的解释。

1. 当 char [] 作为函数的参数时, 表示 char *. 当作为函数的参数传入时, 实际上是拷贝了数组的第一个元素的地址。

所以 void test (char a[]) 等同于 void test ( char * a )

char x[10] ;

然后调用 test(x) 则等同于把 x 的第一个元素的地址赋予给参数 a。

2. char * a 和 char a[]

  • 相同点 : a都是指针, 指向char类型。
  • 不同点 : char a[] 把内容存在stack。char *a 则把指针存在 stack,把内容存在 constants。

3. char * a[10] 和 char a[10][20]

  • 相同点 : a 都是2级指针, *a 表示一级指针, **a 表示内存中存储的内容。
  • 不同点 : char * a[10], 数组由char * 类型的指针组成; char a [10][20] 表示一位放10个元素, 二维放20个元素, 值存放地是一块连续的内存区域, 没有指针。

4. 小窍门 : [] 和 * 的数量对应, 如 char a[][] 的指针层数是 2, 相当于 char **a; char *a[] 也是如此, 两层指针. 迷糊的时候数数到底有几个 * 几个 [], 就知道什么情况下存储的是内容还是地址了 ? 如 char a[][] 的情况里面: &a, a, *a 都是地址, **a 是内容。

到此这篇关于C++指针和数组:字符和字符串、字符数组的关联和区别的文章就介绍到这了,更多相关C++字符和字符串、字符数组内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文带你搞懂C语言预处理宏定义

    一文带你搞懂C语言预处理宏定义

    这篇文章主要为大家详细介绍了C语言预处理宏定义#define,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-10-10
  • C++中的引用与高级函数详解

    C++中的引用与高级函数详解

    这篇文章主要介绍了C++中的引用与高级函数详解,概念:引用是为已存在的变量取了一个别名,引用和引用的变量共用同一块内存空间,需要的朋友可以参考下
    2023-07-07
  • 使用C语言判断栈的方向实例

    使用C语言判断栈的方向实例

    下面小编就为大家带来一篇使用C语言判断栈的方向实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,祝大家游戏愉快哦
    2016-12-12
  • 详解c语言中的 strcpy和strncpy字符串函数使用

    详解c语言中的 strcpy和strncpy字符串函数使用

    strcpy 和strcnpy函数是字符串复制函数。接下来通过本文给大家介绍c语言中的strcpy和strncpy字符串函数使用,感兴趣的朋友跟随小编要求看看吧
    2018-10-10
  • C++ 实现对象池的具体方法

    C++ 实现对象池的具体方法

    本文主要介绍了C++ 实现对象池的具体方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • C++编程语言实现单链表详情

    C++编程语言实现单链表详情

    这篇文章主要介绍的是利用C语言实现单链表,实现的是链表中最简单的一种单链表且每个结点中只含有一个指针域,下面将详细举例说明,需要的朋友可以参考一下
    2021-10-10
  • C语言实现学生成绩管理系统课程设计

    C语言实现学生成绩管理系统课程设计

    这篇文章主要为大家详细介绍了C语言实现学生成绩管理系统课程设计,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • 浅析stl序列容器(map和set)的仿函数排序

    浅析stl序列容器(map和set)的仿函数排序

    有序的stl容器在工程中应用什么方便和广泛,但是当我们需要自己的排序的时候,可以用仿函数来设置它
    2013-09-09
  • C++实现LeetCode(37.求解数独)

    C++实现LeetCode(37.求解数独)

    这篇文章主要介绍了C++实现LeetCode(37.求解数独),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C语言实现简单员工工资管理系统

    C语言实现简单员工工资管理系统

    这篇文章主要为大家详细介绍了C语言实现简单员工工资管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03

最新评论