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 main
ouxiaolong@ubuntu:~/share$ ./main
hello 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 main
ouxiaolong@ubuntu:~/share$ ./main
hello world
hello world
hello world
hello 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 main
ouxiaolong@ubuntu:~/share$ ./main
hello world
hello world
hello 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 main
ouxiaolong@ubuntu:~/share$ ./main
hello world
abclo 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 main
ouxiaolong@ubuntu:~/share$ ./main
Segmentation 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 main
ouxiaolong@ubuntu:~/share$ ./main
hello world
hello world
【注1】为何不使用gets函数输入请参看:
《C语言杂记》C语言使用gets函数出现的警告问题_Bruceoxl的博客-CSDN博客_gets函数警告
【注2】为何不使用scanf函数请参看:
《C语言杂记》深入了解scanf() getchar()和gets()等函数之间的区别_Bruceoxl的博客-CSDN博客
《C语言杂记》探讨scanf函数_Bruceoxl的博客-CSDN博客
总结
数组形式:
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); //或使用字符串拷贝函数进行拷贝赋值
———————
作者:Bruceoxl
来源:CSDN
原文:https://bruceou.blog.csdn.net/article/details/88877287
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:
CSDN,CNBLOG博客文章一键转载插件