【C语言学习笔记】输出函数puts()

输出函数 puts()

头文件

stdio.h

函数原型

int puts(const char *string);

功能

向控制台输出一串字符串

即送一字符串到stdout中

参数

输入:字符串指针

输入可以是字符串数组,也可以是字符串常量

思考:
puts()函数的输入是一个字符串指针。当使用一个字符串数组名作为输入时,数组名此时表示一个指向数组的指针值,这符合puts()的输入要求,并能够正确输出。但是,当输入为一个字符串常量时,函数仍然能够正常的输出字符串。
可以作如下猜测:
1.字符串常量的取值实际上是一个地址值,即指针,这样才能够满足puts()函数对输入参数的要求,而这个指针应该指向了字符串常量实际所在的地址。
2.程序运行时,字符串常量将占用内存空间,这样才能保证puts()函数能通过指针找到要输出的数据。
既然字符串常量占用内存,那么应该就能够得到它的地址并输出。

输出:成功标志

函数的返回值为一个整形数据,标志函数执行是否成功。若字符串成功输出,则返回值为非负数(通常为0);若字符串输出失败,则返回值为EOF(通常为-1)。

特性

  1. puts()和printf()都能够用来输出字符串,但是两者有些许不同。puts()在输出字符串后,会自动换行,而printf不会自动换行。两者有如下关系:

    puts(s)↔printf(“%s\n”,s);

  2. puts()函数仍然以’\0’来确定字符串的结尾。

  3. puts()函数只能够输出字符串,参数只能是字符指针。输入若为其他类型数据或指针,编译器报错,无法进行数据类型转换。

实验

这里使用的实验平台为VS2013,不排除在其他平台上会有出现不同实验结果的可能

字符串常量占用内存空间

前面说到,字符串常量在内存中将占用空间,并且能够取得它的地址并输出。下面用实验进行简单的证明。

#include <stdio.h>
int main()
{
    char *p;
    p = "Hello World!";
    printf("%p\n%s\n", "Hello World!", "Hello World!");
    printf("%p\n%s\n", p, p);
    return 0;
}

输出如下

012A5858
Hello World!
012A5858
Hello World!
请按任意键继续. . .

可见字符串本身的取值就是一个指针,而字符串的数据则保存在指针所指向的内存空间。
另外可以发现,对于完全相同的字符串常量,在内存中只会记录一次,而不会重复占用空间。

puts()与printf()

二者最直观的区别就是,是否会自动换行。

#include <stdio.h>
int main()
{
    puts("Hello.");
    printf("Hello.\n" );
    printf("Hello.");
    return 0;
}

输出如下

Hello.
Hello.
Hello.请按任意键继续. . .

前两种输出方式的输出结果完全相同,第三种输出,printf中没有写入换行符,最后输出并没有换行。
可以看出,puts函数在输出时,会自动换行,而printf不会。

字符串长度由’\0’确定

puts输出字符串,从输入指针所指向的字符开始,到遇到的第一个’\0’字符结束。

#include <stdio.h>
int main()
{
    char c[10] = "abcde\0fgh";
    int i;
    puts(c);
    for (i = 0; i < 10; i++)
    {
        putchar(c[i]);
    }
    putchar('\n');
    return 0;
}

输出如下

abcde
abcde fgh
请按任意键继续. . .

可以看到,虽然’\0’以后的字符确实在数组中存在,但是puts并没有对这些字符进行输出。
因此,puts函数输出字符串是以’\0’作为结束标记的。
另外可以看到,在对字符串数组初始化时,数组并没有在’\0’字符处就停止了拷贝,而是将字符串所有的字符全部拷贝进了数组。因此可以了解到,并不是所有对字符串的操作都是以’\0’字符作为结束标记的。
对此思考了一个问题,利用字符串对字符串数组进行初始化时,字符串是以怎样的数据类型进行解析的。

#include <stdio.h>
int main()
{
    char a[10] = "abcde";
    char *p = a;
    char b[10] = p;     //e1
    char c= "abcde";    //e2
    char d[10] = a;     //e3
    char e[10] = (const char[10])a; //e4
    return 0;
}

编译出错,错误提示如下

e1:error C2440: “初始化”: 无法从“char *”转换为“char [10]”
e2:error C2440: “初始化”: 无法从“const char [6]”转换为“char”
e3:error C2075: “d”: 数组初始化需要大括号
e4:error C2440: “类型转换”: 无法从“char [10]”转换为“const char [10]”

从第一个错误信息可以了解到,字符指针不能用来初始化字符数组,也就是说字符串的数据类型并不是字符指针。
那字符串的数据类型到底是什么呢。于是看第二个错误信息。在这里故意将字符串赋值给一个字符变量,这自然是非法的,从而可以让编译器告诉我们,我们在将什么数据类型赋值给字符变量。
从第二个错误信息中,我们就可以了解到,编译器将字符串解析为了字符数组常量,也证实了之前字符串不是指针的推断(指针与数组并不是同一种类型,它们在行为上有些类似,但是实质并不相同)。这也解释了为什么在初始化时,程序能够知道字符串的长度,因为数组类型不同于单纯的指针,它是有长度信息的。
既然初始化用的是常量字符数组,那字符数组变量能用于初始化吗。于是有了错误3和错误4。
错误3告诉我们,字符数组变量不能为字符数组初始化。
错误4告诉我们,尝试将字符数组变量类型转换为字符数组常量是非法的行为。

从上面的分析可以知道,在目前为止本人所知道的数据类型中,不考虑常规的大括号初始化方式,能直接为字符数组初始化的数据类型,就只有字符串,即字符数组常量。

  • 33
    点赞
  • 128
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值