如果想把一个字符串读入程序,首先必须预留储存该字符串的空间,然后用输入函数获取该字符串。
char *name;
scanf("%s",name);
程序11.6 getsputs.c
/* getsputs.c -- using gets() and puts() */
#include <stdio.h>
#define STLEN 81
int main(void){
char words[STLEN];
puts("Enter a string, please.");
gets(words);
printf("Your string twice:\n");
printf("%s\n", words);
puts(words);
puts("Done.");
return 0;
}
下面是该程序在某些编译器(至少是旧式编译器)中的运行示例:
Enter a string, please.
I want to learn about string theory!
Your string twice:
I want to learn about string theory!
I want to learn about string theory!
Done.
整行输入(除了换行符)
程序11.7 fgets1.c
/* fgets1.c -- using fgets() and fputs() */
#include <stdio.h>
#define STLEN 14
int main(void){
char words[STLEN];
puts("Enter a string, please.");
fgets(words, STLEN, stdin);
printf("Your string twice (puts(), then fputs()):\n");
puts(words);
fputs(words, stdout);
puts("Enter another string, please.");
fgets(words, STLEN, stdin);
printf("Your string twice (puts(), then fputs()):\n");
puts(words);
fputs(words, stdout);
puts("Done.");
return 0;
}
程序的输出示例如下:
Enter a string, please.
apple pie
Your string twice (puts(), then fputs()):
apple pie
apple pie
Enter another string, please.
strawberry shortcake
Your string twice (puts(), then fputs()):
strawberry sh
strawberry shDone.
如果pts1和pts2都是指向字符串的指针,那么下面语句拷贝的是字符串的地址而不是字符串本身:
pts2=pts1;
如果希望拷贝整个字符串,要使用strcpy函数。程序11.25要求用户输入以q开头的单词。该程序把输入拷贝至一个临时数组中,如果第1个字母是1,程序调用strcpy把整个字符串从临时数组拷贝至目标数组中。strcpy函数相当于字符串赋值运算符。
程序11.25 copy1.c
/* copy1.c -- strcpy() demo */
#include <stdio.h>
#include <string.h> // declares strcpy()
#define SIZE 40
#define LIM 5
char * s_gets(char * st, int n);
int main(void){
char qwords[LIM][SIZE];
char temp[SIZE];
int i = 0;
printf("Enter %d words beginning with q:\n", LIM);
while (i < LIM && s_gets(temp, SIZE)){
if (temp[0] != 'q')
printf("%s doesn't begin with q!\n", temp);
else{
strcpy(qwords[i], temp);
i++;
}
}
puts("Here are the words accepted:");
for (i = 0; i < LIM; i++)
puts(qwords[i]);
return 0;
}
char * s_gets(char * st, int n){
char * ret_val;
int i = 0;
ret_val = fgets(st, n, stdin);
if (ret_val){
while (st[i] != '\n' && st[i] != '\0')
i++;
if (st[i] == '\n')
st[i] = '\0';
else // must have words[i] == '\0'
while (getchar() != '\n')
continue;
}
return ret_val;
}
下面是该程序的运行示例:
Enter 5 words beginning with q:
quackery
quasar
quilt
quotient
no more
no more doesn't begin with q!
quiz
Here are the words accepted:
quackery
quasar
quilt
quotient
quiz
注意,只有在输入以q开头的单词后才会递增计数器i。
strcpy函数将第二个参数(temp)指向的字符串拷贝至第一个参数(qword[i])指向的数组中。拷贝出来的字符串被称为目标字符串,最初的字符串被称为源字符串,即第一个参数是目标字符串,第二个参数是源字符串。
如果以整型赋值的方式给字符串赋值,那么会报错:
char target[20];
int x;
x = 50; /* assignment for numbers */
strcpy(target, "Hi ho!"); /* assignment for strings */
target = "So long"; /* syntax error */
程序员有责任明确目标数组有足够的空间容纳源字符串的副本,下面的代码存在问题:
char * str;
strcpy(str, "The C of Tranquility"); // a problem
strcy函数把"The C of Tranquility"拷贝到str指向的地址上,但是str未被初始化,所以该字符串有可能被拷贝到任意的地方。
总之,strcpy接受两个字符串指针作为参数,可以把指向源字符串的第二个指针声明为指针、数组名或字符串常量;而指向源字符串副本的的第一个指针应指向一个数据对象(如,数组),且该对象有足够的空间存储源字符串的副本。记住,声明数组将分配储存数据的空间,而声明指针只分配储存一个地址的空间。
strcpy函数还有两个有用的属性。第一,strcpy函数的返回类型是char *,该函数返回的是第一个参数的值,即一个字符的地址。第二,第一个参数不必指向数组的开始。这个属性可用于拷贝数组的一部分。程序12.26演示了该函数的这两个属性:
程序12.26 copy2.c
/* copy2.c -- strcpy() demo */
#include <stdio.h>
#include <string.h> // declares strcpy()
#define WORDS "beast"
#define SIZE 40
int main(void){
const char * orig = WORDS;
char copy[SIZE] = "Be the best that you can be.";
char * ps;
puts(orig);
puts(copy);
ps = strcpy(copy + 7, orig);
puts(copy);
puts(ps);
return 0;
}
程序输出如下:
beast
Be the best that you can be.
Be the beast
beast
注意,strcpy函数把源字符串中的空字符也拷贝在内。在该例中,空字符覆盖了copy数组中that的第一个t,如图11.5所示。注意,由于第一个参数是copy+7,所以ps指向copy中的第八个元素(下标为7)。因此puts(ps)从该处开始打印字符串。
程序 11.27 copy3.c
/* copy3.c -- strncpy() demo */
#include <stdio.h>
#include <string.h> /* declares strncpy() */
#define SIZE 40
#define TARGSIZE 7
#define LIM 5
char * s_gets(char * st, int n);
int main(void){
char qwords[LIM][TARGSIZE];
char temp[SIZE];
int i = 0;
printf("Enter %d words beginning with q:\n", LIM);
while (i < LIM && s_gets(temp, SIZE)){
if (temp[0] != 'q')
printf("%s doesn't begin with q!\n", temp);
else{
strncpy(qwords[i], temp, TARGSIZE - 1);
qwords[i][TARGSIZE - 1] = '\0';
i++;
}
}
puts("Here are the words accepted:");
for (i = 0; i < LIM; i++)
puts(qwords[i]);
return 0;
}
char * s_gets(char * st, int n){
char * ret_val;
int i = 0;
ret_val = fgets(st, n, stdin);
if (ret_val){
while (st[i] != '\n' && st[i] != '\0')
i++;
if (st[i] == '\n')
st[i] = '\0';
else // must have words[i] == '\0'
while (getchar() != '\n')
continue;
}
return ret_val;
}
下面是该程序的运行示例:
Enter 5 words beginning with q:
quack
quadratic
quisling
quota
quagga
Here are the words accepted:
quack
quadra
quisli
quota
quagga
strncpy(target,source,n)把source中的n个字符或空字符之前的字符拷贝到target中。因此,如果source中的字符数小于n,则拷贝整个字符串,包括空字符。但是,strncpy拷贝字符串的长度不会超过n,如果拷贝到第n个字符时还未拷贝完整个源字符串,就不会拷贝空字符。所以,拷贝的副本中不一定有空字符。鉴于此,该程序把n设置为比目标数组大小小1,然后把数组最后一个元素设置为空字符。
这样做确保储存的是一个字符串。如果目标空间能容纳源字符串的副本,那么从源字符串拷贝的空字符串便是该副本的结尾;如果目标空间装不下副本,则把副本最后一个元素设置为空字符。