在C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中,字符数组实际上是一系列字符的集合,也就是字符串(String)。在C语言中,没有专门的字符串变量,没有string类型,通常就用一个字符数组来存放一个字符串。C语言规定,可以将字符串直接赋值给字符数组。

例如:

char str[30] = {"c.zhongguo.com"};//可以使用str[i]来访问元素
char str[30] = "c.zhongguo.com";  //这种形式更加简洁,实际开发中常用//也可以不指定长度

数组第 0 个元素为'c',第 1 个元素为'.',第 2 个元素为'z',后面的元素以此类推。

首先明确一点,同数组一样字符串中的所有字符在内存中是连续排列的。

先观察一下下边的输出:

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;int main() {char str[] = "http://c.biancheng.net";char *pstr = str;//将字符串首地址给它cout << str << endl;//输出http://c.biancheng.netprintf(str);输出http://c.biancheng.net//最正规的是使用上格式控制符%s输出字符串,%p输出地址。return 0;
}

结果展示:

总结:字符数组归根结底还是一个数组,上节讲到的关于指针和数组的规则同样也适用于字符数组。

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;int main() {char str[] = "china.zhongguo.com";//未定义长度//p 指向的数组元素是 char 类型,所以 p 的类型必须也是char *char *pstr = str;//定义一个指针变量pstr,该指针变量初始化为str字符数组即字符串的首地址。int len = strlen(str), i;//使用*(pstr+i)for (i = 0; i<len; i++) {printf("%c", *(pstr + i));//先地址加再取元素}printf("\n");//使用pstr[i] 就是上节课里边的p[i]即地址[i]for (i = 0; i<len; i++) {printf("%c", pstr[i]);}printf("\n");//使用*(str+i)for (i = 0; i<len; i++) {printf("%c", *(str + i));}printf("\n");return 0;
}

结果展示:

----------以上是使用字符数组来表示字符串,所以除了字符数组,C语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串,如下:(此处为什么直接将字符串赋给指针变量,需要不是应该是地址吗?,规定直接使用一个指针指向字符串

char *str = "ABC//DEF.COM";
//或者
char *str;
str = "http://c.biancheng.net";//此处为什么直接将字符串赋给指针变量

字符串中的所有字符在内存中是连续排列的,str 指向的是字符串的第 0 个字符;我们通常将第 0  个字符的地址称为字符串的首地址。字符串中每个字符的类型都是char,所以 str 的类型也必须是char *

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;int main() {char *str = "ABC//DEF.COM";int len = strlen(str), i;//直接输出字符串printf("%s\n", str);//使用*(str+i)for (i = 0; i<len; i++) {printf("%c", *(str + i));//地址先加再取元素}printf("\n");//使用str[i]for (i = 0; i<len; i++) {printf("%c", str[i]);//使用地址[i]取数据}printf("\n");return 0;
}

结果展示:

这样去取元素的方式和字符数组是非常相似,它们都可以使用%s输出整个字符串,都可以使用*[ ]获取单个字符,但是这两种表示字符串的方式还是有区别的,它们最根本的区别是在内存中的存储区域不一样,字符数组存储在全局数据区或栈区,第二种形式的字符串存储在常量区。全局数据区和栈区的字符串(也包括其他数据)有读取和写入的权限,而常量区的字符串(也包括其他数据)只有读取权限,没有写入权限。

内存权限的不同导致的一个明显结果就是,字符数组在定义后可以读取和修改每个字符,而对于第二种形式的字符串,一旦被定义后就只能读取不能修改,任何对它的赋值都是错误的。

我们将第二种形式的字符串称为字符串常量,意思很明显,常量只能读取不能写入。请看下面:

#include <stdio.h>
int main()
{char *str = "Hello China!";str = "I love C!";  //正确str[3] = 'P';  //错误return 0;
}

这段代码能够正常编译和链接,但在运行时会出现段错误(Segment Fault)或者写入位置错误。

第5行代码是正确的,可以更改指针变量本身的指向;第6行代码是错误的,不能修改字符串中的字符。

到底使用字符数组还是字符串常量

在编程过程中如果只涉及到对字符串的读取,那么字符数组和字符串常量都能够满足要求;如果有写入(修改)操作,那么只能使用字符数组,不能使用字符串常量。

获取用户输入的字符串就是一个典型的写入操作,只能使用字符数组,不能使用字符串常量,请看下面的代码:

#include <stdio.h>
int main(){char str[30];gets(str);printf("%s\n", str);return 0;
}

PS总结:最后我们来总结一下,C语言有两种表示字符串的方法,一种是字符数组,另一种是字符串常量,它们在内存中的存储位置不同,使得字符数组可以读取和修改,而字符串常量只能读取不能修改。

C指针5:字符串指针(指向字符串的指针)相关推荐

  1. 指针数组,数组指针,存放数组指针的数组,指向存放数组指针数组的指针,函数指针,函数指针数组,指向函数指针数组的指针

    数组: 一组数据的集合称为数组,它所包含的每一个数据叫做数组元素,例如 int a[4]: 它定义了一个长度为4的整型数组,名字是a . 一般的定义数组可以用 :数据类型 数组名 [数组长度]:来声明 ...

  2. 20返回指针的函数与指向函数的指针

    一.返回指针的函数 指针也是C语言中的一种数据类型,因此一个函数的返回值肯定可以是指针类型的. 返回指针的函数的一般形式为:类型名 * 函数名(参数列表) 比如下面这个函数,返回一个指向char类型变 ...

  3. 【错误记录】C 语言中通过指针操作字符串常量出错记录 ( 只有 栈内存 或 堆内存 中的数据才能通过指针修改 | 不要通过指针修改常量区的字符串 )

    文章目录 一.报错记录 二.修改方案 一.报错记录 执行下面的代码 , 报错如下 : 执行的错误代码 : #include <stdio.h> #include <stdlib.h& ...

  4. 【C语言学习笔记】26. 指针(3)指向指针的指针、传递指针给函数

    前言 指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链.通常,一个指针包含一个变量的地址.当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置. ...

  5. C指针8:二级指针(意思就是指向指针的指针)

    指针可以指向一份普通类型的数据,例如 int.double.char 等,以下简称一级指针: 也可以指向一份指针类型的数据,例如 int *.double *.char * 等.以下简称二级指针:即如 ...

  6. C++基础之指向成员的指针

    C++中指向成员的指针 一个类有两种基本的成员:函数成员和数据成员.同样的,指向成员的指针也有两种:指向函数成员的指针和指向数据成员的指针.后则其实并不常用,因为类一般是不含有公共数据成员的,仅当用在 ...

  7. [C++基础]018_常量指针和指向常量的指针

    先来看一下什么是常量指针,什么是指向常量的指针吧! 1. 常量指针定义 1 int * const ptr = new int(); 2. 指向常量的指针 1 const int* ptr; 上面已经 ...

  8. 【C/C++学习】之七、指向函数的指针

    什么是指向函数的指针 函数指针是指向函数的指针变量,不是指向对象的指针!函数指针本身应该是"指针变量": "在C语言中,函数本身不是变量,但可以定义指向函数的指针,这种指 ...

  9. C语言 指向函数的指针

    C语言程序在编译后,每个函数都有一个首地址(也就是函数第一条指令的地址),这个地址称为函数的指针.可以定义指向函数的指针变量,使用指针变量间接调用函数. 先用一个简单的程序来说明: #include ...

  10. C语言中指向函数的指针(我见过的讲的最清晰的文章)

    转帖自: http://wenku.baidu.com/view/7e566448cf84b9d528ea7a57.html 1 定义和调用 程序在编译后,每个函数都有一个首地址(也就是函数第一条指令 ...

最新文章

  1. 计算机课堂有趣的游戏,有趣的课堂游戏作文9篇
  2. lintcode:删除链表中指定元素
  3. Serverless Kubernetes 入门:对 Kubernetes 做减法
  4. poj-2115 C Looooops(扩展欧几里得)
  5. 这是一份编程宝典,请查收!
  6. java语言概述、java语言特性、java语言发展史、java语言作用
  7. Julia面向对象(多重派发)
  8. 840. 模拟哈希表(模板)
  9. protues 快捷键和元件
  10. Oh Mathematic, Oh God,太美了
  11. 书城项目 软件可行性分析报告
  12. Oracle 12C 最新补丁下载与安装操作指北
  13. 英语词性的分类及用法详述
  14. python曲线拟合准确度评估_使用Python SciPy量化曲线拟合的质量
  15. 新买的硬盘接在计算机上,电脑如何对刚买来的新硬盘分区
  16. PTA航空公司VIP客户查询c++版——山东科技大学
  17. 移动Web第七天(响应式网页:媒体查询、BootStrap)
  18. 《沈剑架构师训练营》第3章 - 快速性能优化
  19. MySQL 精选 60 道笔试题
  20. MySQL练习题全部

热门文章

  1. Thread start()方法和run()方法的区别
  2. window 10 系统 部分软件打开图标的修改
  3. The form contains the following errors
  4. Android startActivityForResult()的用法
  5. 适定、超定和欠定方程的概念
  6. SQL SERVER 函数ROW_NUMBER() 应用
  7. 研究性能测试工具之systemtap入门指南(四)
  8. .net实现跨页面传值
  9. SQL Server中灾难时备份结尾日志(Tail of log)的两种方法
  10. Standup Timer的MVC模式及项目结构分析