表示字符串和字符串组I/O
前情回顾:字符串是以空字符(\0)结尾的char类型数组
在程序中表示字符串:
//表示字符串的一些方法
#include <stdio.h>
#define MSG "I am a symbolic string constant."
#define MAXLENGTH 81
int main(void)
{
char words[MAXLENGTH] = "I am a string in an array.";//char类型数组
const char * pt1 = "Something is pointing at me.";//指向char的指针
puts("Here are some strings:");//字符串常量
puts(MSG);
puts(words);
puts(pt1);
words[8] = 'p';
puts(words);
return 0;
}
puts函数也属于stdio.h系列的输入/输出函数,但puts函数只显示字符串,而且自动在显示的字符串末尾加上换行符。
显示字符串
在程序中定义字符串
1、字符串字面量(字符串常量)
用引号括起来的内容称为字符串字面量,亦称字符量常量
从ANSI C标准起,如果字符串面量之间没有间隔,或者使用空白字符分隔,C会将其视为串联起来的字符串字面量。如:
char greeting[50] = "Hello, and"" how are" " you"" today!";
与下面的代码等价:
char greeting[50] = "Hello, and how are you today!";
如果要在字符串内使用双引号,必须在双引号前面加上一个反斜杠(\):
printf("\"Run, Spot, run!\" exclaimed Dick.\n");
字符串常量属于静态存储类别,这说明如果在函数中使用字符串常量,该字符串只会被存储一次,在整个程序的生命周期内存在,即使函数被调用多次。
用双引号括起来的内容被视为指向该字符串存储位置的指针。
/* strptr.c -- 把字符串看作指针 */
#include <stdio.h>
int main(void)
{
printf("%s, %p, %c\n", "We", "are", *"space farers");
return 0;
}
结果相当的amazing啊!
字符串看作指针
2、字符串数组与初始化
定义字符串数组时,必须让编译器知道需要多少空间。
一种方法是用足够空间的数组存储的数组存储字符串。
const char m1[40] = "Limit yourself to one line's worth.";
还可以使用指针表示法创建字符串。
const char * pt1 = "Something is pointing at me.";
3、数组形式和指针形式
// addresses.c -- 字符串的地址
#define MSG "I'm special"
#include <stdio.h>
int main()
{
char ar[] = MSG;
const char *pt = MSG;
printf("address of \"I'm special\": %p \n", "I'm special");
printf(" address ar: %p\n", ar);
printf(" address pt: %p\n", pt);
printf(" address of MSG: %p\n", MSG);
printf("address of \"I'm special\": %p \n", "I'm special");
return 0;
}
输出结果:
address of "I'm special": 0x100000f10
address ar: 0x7fff5fbff858
address pt: 0x100000f10
address of MSG: 0x100000f10
address of "I'm special": 0x100000f10
显然pt与MSG地址相同,而ar地址不同。静态数据使用的内存与ar使用的动态内存不同,不仅值不同,特定编译器甚至使用不同的位数表示两种内存。
4、指针形式与数组形式的区别:
char heart[] = "I love Tillie!";
const char *head = "I love Millie!";
最主要的区别是:数组名heart是常量,而指针head是变量
4.1两者都可以使用数组表示法:
for (i = 0; i < 6; i++)
putchar(heart[i]);
putchar('\n');
for (i = 0; i < 6; i++)
putchar(head[i]);
putchar('\n');
输出均为:I love
4.2两者都可以进行指针加法操作
for (i = 0; i < 6; i++)
putchar(*(heart + i));
putchar('\n');
for (i = 0; i < 6; i++)
putchar(*(head + i));
putchar('\n');
4.3但是,只有指针表示法可以进行递增操作:
while (*(head) != '\0') /* 在字符串末尾处停止*/
putchar(*(head++)); /* 打印字符,指针指向下一个位置 */
4.4可以改变heart数组中元素的信息
heart[7]= 'M';或者*(heart + 7) = 'M';
数组的元素是变量(除非数组已经声称为const),但是数组名不是变量
5、字符串数组
// arrchar.c -- 指针数组,字符串数组
#include <stdio.h>
#define SLEN 40
#define LIM 5
int main(void)
{
const char *mytalents[LIM] = {
"Adding numbers swiftly",
"Multiplying accurately", "Stashing data",
"Following instructions to the letter",
"Understanding the C language"
};
char yourtalents[LIM][SLEN] = {
"Walking in a straight line",
"Sleeping", "Watching television",
"Mailing letters", "Reading email"
};
int i;
puts("Let's compare talents.");
printf("%-36s %-25s\n", "My Talents", "Your Talents");
for (i = 0; i < LIM; i++)
printf("%-36s %-25s\n", mytalents[i], yourtalents[i]);
printf("\nsizeof mytalents: %zd, sizeof yourtalents: %zd\n",
sizeof(mytalents), sizeof(yourtalents));
return 0;
}
字符串数组
显然,两者十分相似,但也有区别。mytalents数组是一个内含5个指针的数组,而yourtalents数组是一个内含5个数组的数组,每个数组内含40个char类型的值。mytalents中的指针指向初始化时所用的字符串字面量的位置,这些字符串字面量被存储在静态内存中;而yourtalents中的数组则存储着字符字面量的副本,所以每个字符都被存储两次。此外,为字符串数组分配内存的使用率较低。yourtalents中每个元素大小必须相同,而且必须是能存储最长字符串的大小
总而言之,如果要用数组表示一系列待显示的字符串,那么使用指针数组,效率更高。但是,指针数组指向的字符串字面量不能更改。