C指针5:字符串指针(指向字符串的指针)

在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.net
	printf(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语言有两种表示字符串的方法,一种是字符数组,另一种是字符串常量,它们在内存中的存储位置不同,使得字符数组可以读取和修改,而字符串常量只能读取不能修改。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章