1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 《C语言杂记》C语言字符数组与字符指针(指向字符串的指针)详解

《C语言杂记》C语言字符数组与字符指针(指向字符串的指针)详解

时间:2021-01-13 00:56:31

相关推荐

《C语言杂记》C语言字符数组与字符指针(指向字符串的指针)详解

C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中,字符数组用法很简单我们还是来你看个例子吧。

#include <stdio.h>#include <string.h>int main(){char str[] = "hello world!\n";int len = strlen(str), i;//直接输出字符串printf("%s", str);//每次输出一个字符for(i=0; i<len; i++){printf("%c", str[i]);}return 0;}

运行结果:

ouxiaolong@ubuntu:~/share$ gcc main.c -o mainouxiaolong@ubuntu:~/share$ ./mainhello world!hello world!

字符数组归根结底还是一个数组,上节讲到的关于指针和数组的规则同样也适用于字符数组。更改上面的代码,使用指针的方式来输出字符串:

#include <stdio.h>#include <string.h>int main(){char str[] = "hello world";char *p = str;int len = strlen(str), i;//直接打印printf("%s\n", p);//使用*(p+i)for(i=0; i<len; i++){printf("%c", *(p+i));}printf("\n");//使用p[i]for(i=0; i<len; i++){printf("%c", p[i]);}printf("\n");//使用*(str+i)for(i=0; i<len; i++){printf("%c", *(str+i));}printf("\n");return 0;}

运行结果:

ouxiaolong@ubuntu:~/share$ gcc main.c -o mainouxiaolong@ubuntu:~/share$ ./mainhello worldhello worldhello worldhello world

除了字符数组,C语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串,例如:

char *str = "hello world";

或者:

char *str;str = "hello world";

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

下面的例子演示了如何输出这种字符串:

#include <stdio.h>#include <string.h>int main(){char *str = "hello world";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]);}printf("\n");return 0;}

运行结果:

ouxiaolong@ubuntu:~/share$ gcc main.c -o mainouxiaolong@ubuntu:~/share$ ./mainhello worldhello worldhello world

这一切看起来和字符数组是多么地相似,它们都可以使用%s输出整个字符串,都可以使用*或[ ]获取单个字符,这两种表示字符串的方式是不是就没有区别了呢?

有!它们最根本的区别是在内存中的存储区域不一样,字符数组存储在全局数据区或栈区,字符指针的字符串存储在常量区。全局数据区和栈区的字符串(也包括其他数据)有读取和写入的权限,而常量区的字符串(也包括其他数据)只有读取权限,没有写入权限。

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

为了进一步说明字符指针,我们接下来还要对其深入剖析,字符指针的字符串称为字符串常量,意思很明显,常量只能读取不能写入。

首先来看看字符数组的例子。

#include <stdio.h>int main(){char str[] = "hello world\n";printf("%s", str);str[0] = 'a';str[1] = 'b';str[2] = 'c';printf("%s", str);return 0;}

结果如下:

ouxiaolong@ubuntu:~/share$ gcc main.c -o mainouxiaolong@ubuntu:~/share$ ./mainhello worldabclo world

再来看看字符指针的例子,看看有何不同。

#include <stdio.h>int main(){char *str = "hello world\n";str = "I love C!"; //正确str[3] = 'P'; //错误printf("%s",str);return 0;}

结果如下:

ouxiaolong@ubuntu:~/share$ gcc main.c -o mainouxiaolong@ubuntu:~/share$ ./mainSegmentation fault (core dumped)

这段代码能够正常编译和链接,但在运行时会出现段错误(Segment Fault)或者写入位置错误。第6行代码是正确的,可以更改指针变量本身的指向;第5行代码是错误的,不能修改字符串中的字符。

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

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

#include <stdio.h>#include <string.h>int main(){char str[30];fgets(str,30,stdin);str[strlen(str)-1] = '\0';printf("%s\n", str);return 0;}

运行结果:

ouxiaolong@ubuntu:~/share$ gcc main.c -o mainouxiaolong@ubuntu:~/share$ ./mainhello worldhello world

【注1】为何不使用gets函数输入请参看:

/u013162035/article/details/88565627

【注2】为何不使用scanf函数请参看:

/u013162035/article/details/78620842

/u013162035/article/details/78620827

总结

数组形式:

char str[] = “hello world"; //栈(局部)

字符指针形式:

char *str = “hello world"; //文字常量区

数组形式与字符指针形式都是字符串的表示形式,但是这两种表示形式大不相同。

下面以数字形式字符串char str[] = “hello world"; 与指针形式字符串char *str = “hello world”;为例:

1、储存方式

(1)字符数组由若干元素组成,每个元素存放一个字符,

(2)而字符指针变量只存放字符串的首地址,不是整个字符串。

2、存储位置

(1)数组是在内存中开辟了一段空间存放字符串;

(2)而字符指针是在文字常量区开辟了一段空间存放字符串,将字符串的首地址付给指针变量str。

3、赋值方式

对与数组,下面的赋值方式是错误的:

char str[10];str="hello";

而对字符指针变量,可以采用下面方法赋值:

char *a;a="hello";

4、可否被修改

(1)指针变量指向的字符串内容不能被修改,但指针变量的值(即存放的地址或者指向)是可以被修改的;

例一:指针变量指向的字符串内容不能被修改

char *p = “hello”; //字符指针指向字符串常量

p = ‘a’; //错误,常量不能被修改,即指针变量指向的字符串内容不能被修改

说明:定义一个字符指针指向字符串常量“hello”,修改指针变量指向的字符串的内容,即p = ‘a’,发生错误,指针变量指向字符串常量,而常量字符串存在文字常量区,这段空间中的内容为只读内容,不能被修改,即指针变量指向的字符串内容不能被修改。

例二:指针变量的值可以被修改

char *p = "hello"; //字符指针指向字符串常量char ch = 'a';p = &ch; //指针变量指向可以改变

说明:定义一个字符指针指向字符串常量“hello”,同时定义一个字符变量ch,改变指针变量的指向,即让p指向字符变量ch,这样是可以的,即指针变量的指向是可以改变的。

(2)字符串数组内容可以被修改,但字符串数组名所代表的字符串首地址不能被修改

例子:定义了一个数组buf,编译器在编译时为它分配内存单元,有确定的地址,此例子中为0X0034FDCC,给buf赋不同的值,字符串数组数组名所代表的字符串首地址没有改变,一直为0X0034FDCC。

5、初始化

定义了一个数组,在编译时为他分配内存单元,他有确定的地址;而在定义一个字符指针变量时,最好将其初始化,否则指针变量的值会指向一个不确定的内存段,将会破坏程序,以下方式是允许的:

char str[10];scanf("%s", str); //或使用字符串拷贝函数进行拷贝赋值

以下方式不推荐,是很危险的:

char *p; //指针变量未初始化,指向一个不确定的内存段scanf("%s", p);

以下方式是推荐使用的:

char *p = NULL;p = (char *)malloc(10);scanf("%s", p); //或使用字符串拷贝函数进行拷贝赋值

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。