表示字符串和字符串I/O
字符串是以空字符’\0’结尾的char类型数组,字符串在我们的编程生活中特别常用,因此C提供了许多专门用于处理字符串的函数。接下来我们将从字符串的I/O开始探讨。
#include "stdio.h"
#define MSG "I am a symbolioc string constant" //1.字符串常量
#define MAXLENGTH 81
int main(){
char words[MAXLENGTH]="I am a string in an array"; //2.用字符数组存储
const char *pt1="Something is pointing at me"; //3.用字符类型指针指向
puts("Here are some strings:");
puts(MSG);
puts(words);
puts(pt1);
words[8]='p';
puts(words);
return 0;
}
结果如下:
puts() 函数与printf()函数一样,都输入stdio.h头文件中定义的输入/输出函数,但是puts()与众不同的地方在于,puts()函数只显示字符串,而且自动在显示的字符串末尾加上换行符,相信大家在输出的结果中也能看到。
在程序中定义字符串
1.字符串字面量(字符串常量)
用双引号括起来的内容称为字符串字面量,也叫做字符串常量。值得注意的是,双引号中的字符和编译器自动加入末尾的\0字符,都作为字符串储存在内存中。这里有两个需要注意的小细节。
1.如果字符串字面量之间没有间隔,或者用空白字符分割,C会将其视为串联起来的字符串字面量.
#include "stdio.h"
#define MSG "I am a symbolioc string constant"
#define MAXLENGTH 81
int main(){
char words[MAXLENGTH]="I am a string in an array";
char word[MAXLENGTH]="I am a string"" in an"" array";
printf("\nwords=");
puts(words);
printf("\nword=");
puts(word);
return 0;
}
2.如果要在字符串内部使用双引号,必须在双引号前面加上一个反斜杠(\)
printf(" \" i love you \", he say");
结果如下
最后不妨一提的是,字符串常量属于静态存储类别 ,这说明如果在函数中使用字符串常量,该字符只会被存储一次,在整个程序的生命周期内存在,即使函数被调用多次。
2.数组和指针
字符串的数组形式和指针形式有何不同? 我们直接开门见山。
#define MSG "I am special"
#include "stdio.h"
int main(){
char ar[] =MSG;
const char *pt=MSG;
printf("\n address of \"I am special \" : %p","I am special");
printf("\n address ar:%p",ar);
printf("\n address pt:%p",pt);
printf("\n address of MSG:%p",MSG);
printf("\n address of \"I am special \" : %p\n","I am special");
return 520;
}
输出结果如下
从这个结果中我们可以得到以下几点结论:
- pt 与MSG的地址相同,而ar的地址不同
- 字符串面量"I am special"在程序的两个printf 函数中出现两次,但是编译器只使用了一个存储位置,而且与MSG的地址相同。
- 静态数据使用的内存与ar使用的动态内存不同。不仅值不同,特定编译器甚至使用不同的位数表示两种内存
综上所述,初始化数组把静态存储区的字符串拷贝到数组中,而初始化指针只是把字符串的地址拷贝给指针。
字符串的指针表示
在这里我们仅探讨一个小细节,不管是复习指针概念也好,还是提高编程细节也好。
char *word="frame";
word[1]='l';
这样是否被允许呢?在我认为,编译器可能允许这样做,但是对当前C语言标准而言,这样的行为是未定义,比如这样的语句可能导致内存访问错误。
#include "stdio.h"
int main(){
char *pl="Kinggon";
pl[0] = 'F'; //OK?
printf("Kinggon");
printf(":Beware the %ss!\n","Kinggon");
return 520;
}
这会导致什么样的结果呢? 有的编译器可以用相同的地址替换每个“Kinggon”。输出结果为:
Finggon: Beware the Finggon!
当然,一些编译器会由于这方面的原因,其行为难以捉摸,另一些编译器会导致程序异常中断(在我实验的C-Free5编译器以及DEV-C++中便是如此)
因此,推荐用法如下:
const char *p1="Kinggon";