第11章 字符串和字符串函数(3 字符串输出)

发布于 2021-09-09  630 次阅读


11.3 字符串输出

C有3个标准库函数用于打印字符串:puts(),fputs()和printf().

11.3.1 puts()函数

puts()函数很容易使用,只需把字符的地址作为参数传递给它即可。
//put_out.c --使用put()
#include<stdio.h>
#define DEF "I am a #define string"
int main(void)
{
    char str1[80] = "An array was initialized to me.";
    const char *str2 = "A pointer was initialized to me.";

    puts("I'm an argument to puts()");
    puts(DEF);
    puts(str1);
    puts(str2);
    puts(&str1[5]);
    puts(str2 + 4);

    return 0;
 } 

file

如上所示,每个字符串独占一行,因为puts()在显示字符串时会自动在其末尾添加一个换行符。
该程序示例再此说明,用双引号括起来的内容是字符串常量,且被视为该字符串的地址另外,储存字符串的数组名也被看作是地址。在第5个puts()调用中,表达式&str1[5]是str1数组的第6个元素(r),puts()从该元素开始输出。于此类似,第6个puts()调用中,str2+ 4指向存储“pointer”中的i的存储单元,puts()从这里开始输出。
puts()如何知道在何处停止?该函数在遇到空字符时就停止输出,所以必须确保有空字符,不要模仿下述程序,
// nono.c       --千万不要模仿
#include<stdio.h>
int main(void)
{
    //char side_a[] = "Side A";
    char dont[] = {'W','O','W','!'};
    //char side_b[] = "Side B";

    puts(dont);             //dont不是一个字符串

    return 0; 
 } 
由于dont缺少一个表示结束的空字符,所以它不是一个字符串,因此puts()不知道在何处停止,他会一直打印dont后面内存中的内容,知道发现一个字符为止。为了让puts()能尽快读到空字符,我们把dont放在side_a和side_b之间。
我们使用编译器把side_a数组存储在dont数组之后,所以puts()一直输出至遇到side_a中的空字符。你所使用的编译器输出的内容可能不同,这取决于编译器如何在内存中存储数据。如果删除程序中的side_a和side_b数组,通常内存总有许多空字符,如果幸运的话,puts()很快就会发现一个。
但是这样做很不靠谱。

11.3.2 fputs()函数

fputs()函数是puts()针对文件定制的版本。它们的区别如下:
- fput()函数的第2个参数指明要写入的数据文件。如果要打印在显示器上,可以用定义在stdio.h中的stdout(标准输出)作为参数。
- 与puts()不同,fputs()不会在输出的末尾添加换行符。
gets()丢弃输入行中的换行符,但是puts()在输出中添加换行符。另一方面,fgets()保留输入中的换行符,fputs()不再在输出中添加换行符。假设要编写一个循环,读取一行。另起一行打印出该输出。可以这样写:
char line[81];
while(gets(line))   //与while(gets(line)!=NULL)相同
    puts(line);
如果gets()读到文件结尾会返回空指针。对空指针为0,这样可以结束循环;还可以这样写:
char line[81];
while(fgets(line,81,stdin))
    fputs(line,81);
第一个循环,line数组中的字符串显示在下一行,因为puts()末尾添加了一个换行符。第2个循环,line数组中的字符也显示在下一行,因为fgets()把换行符存储在字符串末尾,注意,如果混个使用fgets()输入和puts()输出,每个待显示的字符串末尾就会有两个换行符。这里关键注意fgets()和fputs()配对使用,gets()和puts()配对使用。

11.3.3 printf()函数

和puts()一样,printf()也把字符串的地址作为参数。printf()函数用起来没有puts()函数那么方便,但是它更加多才多艺,因为它可以格式化不同的数据类型。
与puts()不同的是,printf()不会自动的在每个字符串末尾加上一个换行符。因此,必须在参数中指明应该在那里使用换行符。
printf("%s\n",string);
和下面的语句效果相同:
puts(string);
如上所示,printf()的形式更复杂些,需要输入更多的代码,而且计算机执行的时间也更长。然而使用printf()打印多个字符串更加简单,例如,下面语句把well、用户名和一个#define定义的字符串打印在一行:
printf("Well,%s,%s\n",name,MSG);

11.4 自定义输入/输出函数

不一定要使用C库中的标准函数,如果无法使用这些函数或者不想使用它们,完全可以在getchar()和putchar()的基础上自定义所需的函数。假设你需要一个类似puts()但是不会自动添加换行的函数
//put1.c        -- 打印字符串不添加\n
#include<stdio.h>
void put1(const char *string)       //不会改变字符串
{
    while(*string !='\0')
        putchar(*string++);
}
指向char的指针string最初指向传入参数的首元素,因为该函数不会改变传入的字符串,所以形参使用了const限定符,打印了首元素的内容后,指针递增1,指向下一个元素。while循环重复这一过程,直到指针指向包含空字符的元素,记住,++的优先级高于*,因此putchar(*string++)打印string指向的值,递增的是string本身,而不是递增塔档所指向的字符。
可以把put1.c程序作为编写字符串处理函数的模型。因为每个字符串都以空字符结尾,所以不用给函数传递字符串的大小。函数依次处理每个字符,直至遇到空字符。
用用数组编写这个函数稍微复杂些:
int i=0;
while(string[i]!='\0')
    putchar(string[i++]);
要为数组索引创建一个额外的变量:
许多C程序员会在while循环中使用下面的测试条件:
while(*string)
当string指向空字符,*string的值是0,即测试条件为假,while循环结束。这种方法比上上面两种方法简洁。
为什么程序清单中的形式参数是const char *string.而不是const char string[]?从技术方面看,两者等价且都有效。使用带方括号的写法是为了提醒用户:该函数处理的是数组。然而,如果要处理字符串,实际参数可以是数组名,用双引号括起来的字符串,或声明char *类型的变量。用const char *string可以提醒用户:实际参数不一定是数组。
假设要设计一个类似puts的函数,而且该函数还给出待打印字符的个数。
//put2.c 打印一个字符串,并统计打印的字符数 
#include<stdio.h>
int put2(const char *string)
{
    int count = 0;
    while(*string)
    {   
        putchar(*string++);
        count++;
    }
    putchar('\n');    //不统计换行符 

    return count; 
}
//例子
//put2.c 打印一个字符串,并统计打印的字符数 
#include<stdio.h>
int put2(const char *string);
int main(void)
{   
    int a;
    a = put2("Guoan");
    printf("%d",a);
    return 0;
}
int put2(const char *string)
{
    int count = 0;
    while(*string)
    {   
        putchar(*string++);
        count++;
    }
    putchar('\n');    //不统计换行符 

    return count; 
}

file

下面的函数调用奖打印字符串pizza:
put1("pizza");
下面的调用返回统计的字符数,并且奖其赋给num:
num = put2("pizza");
下一程序演示了一个简单的驱动程序测试put1()和put2()并演示了嵌套韩式的调用:
//put_put.c     --用户自定义输出函数
#include<stdio.h>
void put1(const char *string);
int put2(const char *string);
int main(void)
{
    put1("If i'd as much money");
    put1(" as I could spend,\n");
    printf("I could %d characters.\n",put2("I nerver would cry old chairs to mend."));

    return 0;
}
void put1(const char *string)
{
    while(*string)
        putchar(*string++);
}
int put2(const char *string)
{
    int count = 0;
    while(*string)
        {
            putchar(*string++);
            count++;
        }
    putchar('\n');

    return count;
}

file

printf()为了获取put2的返回值先执行put2所以结果如上所示。

擦肩而过的概率