C语言 - 输入&输出

C语言 输入 & 输出

当我们提到输入时,这意味着要向程序填充一些数据。输入可以是以文件的形式或从命令行中进行。C 语言提供了一系列内置的函数来读取给定的输入,并根据需要填充到程序中。

当我们提到输出时,这意味着要在屏幕上、打印机上或任意文件中显示一些数据。C 语言提供了一系列内置的函数来输出数据到计算机屏幕上和保存数据到文本文件或二进制文件中。

 

1. 标准文件

C 语言把所有的设备都当作文件。所以设备(比如显示器)被处理的方式与文件相同。以下三个文件会在程序执行时自动打开,以便访问键盘和屏幕。

标准文件 文件指针 设备
标准输入 stdin 键盘
标准输出 stdout 屏幕
标准错误 stderr 您的屏幕

文件指针是访问文件的方式,本节将讲解如何从键盘上读取值以及如何把结果输出到屏幕上。

C 语言中的 I/O (输入/输出) 通常使用 printf() 和 scanf() 两个函数。

scanf() 函数用于从标准输入(键盘)读取并格式化, printf() 函数发送格式化输出到标准输出(屏幕)。

实例:

#include <stdio.h>      // 执行 printf() 函数需要该库
int main()
{
    printf("菜鸟教程");  //显示引号中的内容
    return 0;
}

编译以上程序,输出结果为:

菜鸟教程

实例解析:

  • 所有的 C 语言程序都需要包含 main() 函数。 代码从 main() 函数开始执行。
  • printf() 用于格式化输出到屏幕。printf() 函数在 "stdio.h" 头文件中声明。
  • stdio.h 是一个头文件 (标准输入输出头文件) and #include 是一个预处理命令,用来引入头文件。 当编译器遇到 printf() 函数时,如果没有找到 stdio.h 头文件,会发生编译错误。
  • return 0; 语句用于表示退出程序。

 

2. getchar() 和 putchar() 函数

int getchar(void) 函数从屏幕读取下一个可用的字符,并把它返回为一个整数。这个函数在同一个时间内只会读取一个单一的字符。您可以在循环内使用这个方法,以便从屏幕上读取多个字符。

int putchar(int c) 函数把字符输出到屏幕上,并返回相同的字符。这个函数在同一个时间内只会输出一个单一的字符。您可以在循环内使用这个方法,以便在屏幕上输出多个字符。

请看下面的实例:

实例:

#include <stdio.h>
 
int main( )
{
   int c;
 
   printf( "Enter a value :");
   c = getchar( );
 
   printf( "\nYou entered: ");
   putchar( c );
   printf( "\n");
   return 0;
}

当上面的代码被编译和执行时,它会等待您输入一些文本,当您输入一个文本并按下回车键时,程序会继续并只会读取一个单一的字符,显示如下:

$./a.out
Enter a value :runoob

You entered: r

 

3. gets() 和 puts() 函数

char *gets(char *s) 函数从 stdin 读取一行到 s 所指向的缓冲区,直到一个终止符或 EOF。

int puts(const char *s) 函数把字符串 s 和一个尾随的换行符写入到 stdout

实例:

#include <stdio.h>
 
int main( )
{
   char str[100];
 
   printf( "Enter a value :");
   gets( str );
 
   printf( "\nYou entered: ");
   puts( str );
   return 0;
}

当上面的代码被编译和执行时,它会等待您输入一些文本,当您输入一个文本并按下回车键时,程序会继续并读取一整行直到该行结束,显示如下:

$./a.out
Enter a value :runoob

You entered: runoob

 

4. scanf() 和 printf() 函数

int scanf(const char *format, ...) 函数从标准输入流 stdin 读取输入,并根据提供的 format 来浏览输入。

int printf(const char *format, ...) 函数把输出写入到标准输出流 stdout ,并根据提供的格式产生输出。

format 可以是一个简单的常量字符串,但是您可以分别指定 %s、%d、%c、%f 等来输出或读取字符串、整数、字符或浮点数。还有许多其他可用的格式选项,可以根据需要使用。如需了解完整的细节,可以查看这些函数的参考手册。现在让我们通过下面这个简单的实例来加深理解:

实例:

#include <stdio.h>
int main( ) {
 
   char str[100];
   int i;
 
   printf( "Enter a value :");
   scanf("%s %d", str, &i);
 
   printf( "\nYou entered: %s %d ", str, i);
   printf("\n");
   return 0;
}

当上面的代码被编译和执行时,它会等待您输入一些文本,当您输入一个文本并按下回车键时,程序会继续并读取输入,显示如下:

$./a.out
Enter a value :runoob 123

You entered: runoob 123

在这里,应当指出的是,scanf() 期待输入的格式与您给出的 %s 和 %d 相同,这意味着您必须提供有效的输入,比如 "string integer",如果您提供的是 "string string" 或 "integer integer",它会被认为是错误的输入。另外,在读取字符串时,只要遇到一个空格,scanf() 就会停止读取,所以 "this is test" 对 scanf() 来说是三个字符串。

 

4.1 %d 格式化输出整数

#include <stdio.h>
int main()
{
    int testInteger = 5;
    printf("testInteger = %d", testInteger);
    return 0;
}

运行结果:

 

4.2 %f 格式化输出浮点数

#include <stdio.h>
int main()
{
	float pi = 3.14;
	printf("pi = %.2f", pi);
    
	while (1);
	return 0;
}

运行结果:

 

4.3 %s 格式化输出字符串

#include <stdio.h>
int main()
{
	char str[25] = "hello word!";
	printf("str = %s", str);

	while (1);
	return 0;
}

运行结果:

 

5. sscanf() 和 sprintf() 函数

在C语言中,sprintf()和sscanf()是两个非常重要且常用的函数,它们分别用于字符串的格式化输出和格式化输入。理解并熟练使用这两个函数,可以极大地提高我们在数据处理和格式转换方面的效率。本文将详细介绍sprintf()和sscanf()函数的用法、原理、常见用例以及注意事项。

5.1. sprintf()函数详解

5.1.1 sprintf()的定义和用法

sprintf()函数用于将格式化的数据写入字符串中,而不是输出到控制台。它的功能类似于printf()函数,但printf()是将格式化的数据输出到标准输出(通常是控制台),而sprintf()是将数据写入一个字符串。

函数原型

int sprintf(char *str, const char *format, ...);
  • str:指向要写入的字符串的指针。
  • format:格式控制字符串,类似于printf()中的格式控制字符串。
  • ...:可变参数,用于指定要格式化的值。

sprintf()返回值为写入字符串的字符数(不包括终止的空字符)。

5.1.2 基本用法

以下是一个简单的示例,展示如何使用sprintf()函数将整数和浮点数格式化为字符串:

#include <stdio.h>
 
int main() {
    char buffer[50];
    int n = 10;
    float f = 3.14;
 
    sprintf(buffer, "Integer: %d, Float: %.2f", n, f);
    printf("%s\n", buffer); // 输出:Integer: 10, Float: 3.14
 
    return 0;
}


在这个示例中,sprintf()将整数n和浮点数f按照格式控制字符串的要求写入buffer中,然后通过printf()输出buffer的内容。

5.1.3 常见格式控制符

sprintf()的格式控制符与printf()相同,常见的格式控制符包括:

  • %d:格式化整数。
  • %f:格式化浮点数。
  • %s:格式化字符串。
  • %c:格式化字符。
  • %x:格式化为十六进制整数。
  • %o:格式化为八进制整数。

以下是一些常见的示例:

#include <stdio.h>
 
int main() {
    char buffer[100];
    
    int a = 255;
    sprintf(buffer, "Decimal: %d, Hex: %x, Octal: %o", a, a, a);
    printf("%s\n", buffer); // 输出:Decimal: 255, Hex: ff, Octal: 377
    
    float pi = 3.14159;
    sprintf(buffer, "Pi: %.2f", pi);
    printf("%s\n", buffer); // 输出:Pi: 3.14
    
    char str[] = "Hello, world!";
    sprintf(buffer, "String: %s", str);
    printf("%s\n", buffer); // 输出:String: Hello, world!
    
    return 0;
}


5.1.4 sprintf()的高级用法

动态分配字符串

有时我们需要处理动态大小的字符串,这时可以使用malloc()函数动态分配内存。例如:

#include <stdio.h>
#include <stdlib.h>
 
int main() {
    char *buffer;
    int n = 10;
    float f = 3.14;
 
    buffer = (char *)malloc(50 * sizeof(char));
    if (buffer == NULL) {
        printf("Memory allocation failed\n");
        return 1;
    }
 
    sprintf(buffer, "Integer: %d, Float: %.2f", n, f);
    printf("%s\n", buffer);
 
    free(buffer);
    return 0;
}


在这个示例中,使用malloc()函数动态分配50字节的内存给buffer,然后将格式化的数据写入buffer,最后使用free()函数释放分配的内存。

字符串拼接

sprintf()还可以用于字符串拼接,例如:

#include <stdio.h>
#include <string.h>
 
int main() {
    char buffer[100] = "Initial string. ";
    char appendStr[] = "Appended string.";
 
    sprintf(buffer + strlen(buffer), "%s", appendStr);
    printf("%s\n", buffer); // 输出:Initial string. Appended string.
 
    return 0;
}


在这个示例中,使用strlen()函数计算buffer的当前长度,然后将appendStr追加到buffer的末尾。

 

5.2. sscanf()函数详解

5.2.1 sscanf()的定义和用法

sscanf()函数用于从字符串中读取格式化的数据。它的功能类似于scanf()函数,但scanf()是从标准输入(通常是键盘)读取数据,而sscanf()是从一个字符串中读取数据。

函数原型

int sscanf(const char *str, const char *format, ...);

 

  • str:指向要读取数据的字符串的指针。
  • format:格式控制字符串,类似于scanf()中的格式控制字符串。
  • ...:可变参数,用于存储读取的数据。

sscanf()返回值为成功读取并赋值的项数。

5.2.2 基本用法

以下是一个简单的示例,展示如何使用sscanf()函数从字符串中读取整数和浮点数:

#include <stdio.h>
 
int main() {
    char buffer[] = "10 3.14";
    int n;
    float f;
 
    sscanf(buffer, "%d %f", &n, &f);
    printf("Integer: %d, Float: %.2f\n", n, f); // 输出:Integer: 10, Float: 3.14
 
    return 0;
}


在这个示例中,sscanf()从buffer字符串中读取一个整数和一个浮点数,并将它们分别存储在n和f中,然后通过printf()输出这些值。

5.2.3 常见格式控制符

sscanf()的格式控制符与scanf()相同,常见的格式控制符包括:

  • %d:读取整数。
  • %f:读取浮点数。
  • %s:读取字符串。
  • %c:读取字符。
  • %x:读取十六进制整数。
  • %o:读取八进制整数。

以下是一些常见的示例:

#include <stdio.h>
 
int main() {
    char buffer[] = "255 ff 377";
    int decimal, hex, octal;
 
    sscanf(buffer, "%d %x %o", &decimal, &hex, &octal);
    printf("Decimal: %d, Hex: %x, Octal: %o\n", decimal, hex, octal); // 输出:Decimal: 255, Hex: ff, Octal: 377
 
    char str[] = "Hello, world!";
    char extractedStr[20];
    sscanf(str, "%s", extractedStr);
    printf("Extracted String: %s\n", extractedStr); // 输出:Extracted String: Hello,
 
    return 0;
}

5.2.4 sscanf()的高级用法

处理复杂字符串

sscanf()可以处理复杂的字符串,例如:

#include <stdio.h>
 
int main() {
    char buffer[] = "Name: John, Age: 25, Height: 5.9";
    char name[20];
    int age;
    float height;
 
    sscanf(buffer, "Name: %s, Age: %d, Height: %f", name, &age, &height);
    printf("Name: %s, Age: %d, Height: %.1f\n", name, age, height); // 输出:Name: John, Age: 25, Height: 5.9
 
    return 0;
}


在这个示例中,sscanf()从buffer字符串中提取了名称、年龄和身高,并分别存储在name、age和height中。

字符串拆分

sscanf()还可以用于字符串拆分,例如:

#include <stdio.h>
 
int main() {
    char buffer[] = "key1=value1;key2=value2;key3=value3";
    char key1[10], value1[10], key2[10], value2[10], key3[10], value3[10];
 
    sscanf(buffer, "%[^=]=%[^;];%[^=]=%[^;];%[^=]=%s", key1, value1, key2, value2, key3, value3);
    printf("%s: %s\n", key1, value1); // 输出:key1: value1
    printf("%s: %s\n", key2, value2); // 输出:key2: value2
    printf("%s: %s\n", key3, value3); // 输出:key3: value3
 
    return 0;
}


在这个示例中,sscanf()通过分隔符将buffer字符串拆分成键值对,并分别存储在对应的变量中。

5.3. sprintf()和sscanf()的实际应用

5.3.1 格式化输出日志

在实际开发中,sprintf()常用于格式化输出日志。例如:

#include <stdio.h>
#include <time.h>
 
void logMessage(const char *level, const char *message) {
    char buffer[100];
    time_t now = time(NULL);
    struct tm *t = localtime(&now);
 
    sprintf(buffer, "[%04d-%02d-%02d %02d:%02d:%02d] [%s] %s",
            t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
            t->tm_hour, t->tm_min, t->tm_sec,
            level, message);
 
    printf("%s\n", buffer);
}
 
int main() {
    logMessage("INFO", "This is an info message.");
    logMessage("ERROR", "This is an error message.");
 
    return 0;
}

在这个示例中,logMessage()函数使用sprintf()将日志级别、消息和当前时间格式化成一个字符串,然后输出到控制台。

5.3.2 解析配置文件

sscanf()常用于解析配置文件。例如:

#include <stdio.h>
 
int main() {
    char buffer[] = "username=admin\npassword=12345\n";
    char username[20], password[20];
 
    sscanf(buffer, "username=%s\npassword=%s\n", username, password);
    printf("Username: %s\n", username); // 输出:Username: admin
    printf("Password: %s\n", password); // 输出:Password: 12345
 
    return 0;
}


在这个示例中,sscanf()从配置字符串中提取用户名和密码,并分别存储在username和password中。

5.3.3 处理命令行输入

sscanf()还可以用于处理命令行输入。例如:

#include <stdio.h>
 
int main() {
    char command[] = "add 10 20";
    char cmd[10];
    int a, b;
 
    sscanf(command, "%s %d %d", cmd, &a, &b);
    if (strcmp(cmd, "add") == 0) {
        printf("Result: %d\n", a + b); // 输出:Result: 30
    }
 
    return 0;
}


在这个示例中,sscanf()从命令字符串中提取命令和参数,然后根据命令执行相应的操作。

5.4. sprintf()和sscanf()的注意事项

5.4.1 缓冲区溢出

使用sprintf()时,需要确保目标字符串有足够的空间存储格式化后的数据,以避免缓冲区溢出。例如:

char buffer[10];
sprintf(buffer, "This is a very long string that exceeds the buffer size."); // 可能导致缓冲区溢出


为了避免缓冲区溢出,可以使用snprintf()函数,指定最大写入字符数:

snprintf(buffer, sizeof(buffer), "This is a very long string that exceeds the buffer size.");

5.4.2 类型匹配

使用sscanf()时,需要确保格式控制符与变量类型匹配。例如:

char buffer[] = "123 abc";
int num;
char str[10];
sscanf(buffer, "%d %s", &num, str); // 格式控制符和变量类型匹配

如果格式控制符与变量类型不匹配,可能导致未定义行为。

 

5.4.3 错误处理

sprintf()和sscanf()在执行过程中可能会遇到各种错误情况,例如格式化字符串不正确、输入数据格式不符合预期等。需要进行适当的错误处理,例如检查返回值、验证输入数据等。

 

5.5. 总结

sprintf()和sscanf()是C语言中两个非常有用的函数,它们分别用于字符串的格式化输出和格式化输入。在本文中,我们详细介绍了这两个函数的定义、用法、常见格式控制符、高级用法、实际应用场景以及注意事项。掌握这些知识,能够帮助我们更高效地处理数据和格式转换,提高程序的可靠性和可维护性。

===========================================

转自:https://blog.csdn.net/mzgxinhua/article/details/140064734

 

posted @   [BORUTO]  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示