12.C 输入 & 输出

C 输入 & 输出

C语言提供了丰富的字符操作函数,用于处理单个字符或字符数组(即字符串)。这些函数主要集中在<ctype.h><string.h><stdio.h>等头文件中。以下是一些常用的C语言字符操作函数的详细介绍:

1.<ctype.h>中的字符分类和转换函数

  • isalnum(c):检查字符c是否为字母(isalpha(c))或数字(isdigit(c))。返回非零值(通常为1)表示是,返回零表示否。例如:

    if (isalnum('A')) {
        printf("A is alphanumeric.\n");
    }
    
  • isalpha(c):检查字符c是否为字母(大写或小写)。返回非零值表示是,返回零表示否。例如:

    if (isalpha('z')) {
        printf("z is an alphabet character.\n");
    }
    
  • isdigit(c):检查字符c是否为十进制数字(0到9)。返回非零值表示是,返回零表示否。例如:

    if (isdigit('3')) {
        printf("3 is a digit.\n");
    }
    
  • islower(c):检查字符c是否为小写字母。返回非零值表示是,返回零表示否。例如:

    if (islower('h')) {
        printf("h is lowercase.\n");
    }
    
  • isupper(c):检查字符c是否为大写字母。返回非零值表示是,返回零表示否。例如:

    if (isupper('X')) {
        printf("X is uppercase.\n");
    }
    
  • isspace(c):检查字符c是否为空格、制表符、换行符等空白字符。返回非零值表示是,返回零表示否。例如:

    if (isspace('\t')) {
        printf("\\t is a whitespace character.\n");
    }
    
  • isxdigit(c):检查字符c是否为十六进制数字(包括0-9A-Fa-f)。返回非零值表示是,返回零表示否。例如:

    if (isxdigit('A')) {
        printf("A is a hexadecimal digit.\n");
    }
    
  • tolower(c):将大写字母字符c转换为小写,其他字符不变。返回转换后的字符。例如:

    char upper = 'Z';
    char lower = tolower(upper);
    printf("'%c' converted to lowercase is '%c'.\n", upper, lower);  // 输出:'Z' converted to lowercase is 'z'.
    
  • toupper(c):将小写字母字符c转换为大写,其他字符不变。返回转换后的字符。例如:

    char lower = 'g';
    char upper = toupper(lower);
    printf("'%c' converted to uppercase is '%c'.\n", lower, upper);  // 输出:'g' converted to uppercase is 'G'.
    

2.<string.h>中的字符串操作函数

  • strlen(str):返回字符串str的长度,不含'\0'的字符数量,即遇到'\0'结束操作。例如:

    const char *text = "Hello, World!";
    int length = strlen(text);
    printf("The string length is %d.\n", length);  // 输出:The string length is 13.
    
  • strcpy(dest, src):将字符串src复制到dest中,覆盖dest原有的内容。返回dest的地址。例如:

    char dest[30];
    const char *src = "Copy this text.";
    strcpy(dest, src);
    printf("Copied string: %s\n", dest);  // 输出:Copied string: Copy this text.
    
  • strncpy(dest, src, n):将src的前n个字符复制到dest中,剩余部分填充为'\0'。返回dest的地址。例如:

    char dest[30];
    const char *src = "Truncate me!";
    strncpy(dest, src, 5);
    printf("Truncated string: %s\n", dest);  // 输出:Truncated string: Trunc
    
  • strcat(dest, src):将字符串src追加到dest的末尾,覆盖dest原有的'\0'并添加新的'\0'。返回dest的地址。例如:

    char dest[30] = "Original ";
    const char *src = "text";
    strcat(dest, src);
    printf("Concatenated string: %s\n", dest);  // 输出:Concatenated string: Original text
    
  • strncat(dest, src, n):将src的前n个字符追加到dest的末尾,覆盖dest原有的'\0'并添加新的'\0'。返回dest的地址。例如:

    char dest[30] = "Partial ";
    const char *src = "append";
    strncat(dest, src, 4);
    printf("Partially concatenated string: %s\n", dest);  // 输出:Partially concatenated string: Partial app
    
  • strcmp(str1, str2):比较字符串str1str2,返回值说明如下:

    • str1小于str2,返回负值。
    • str1等于str2,返回零。
    • str1大于str2,返回正值。例如:
    const char *str1 = "abc";
    const char *str2 = "def";
    int result = strcmp(str1, str2);
    if (result < 0) {
        printf("%s is less than %s.\n", str1, str2);
    } else if (result > 0) {
        printf("%s is greater than %s.\n", str1, str2);
    } else {
        printf("%s and %s are equal.\n", str1, str2);
    }  // 输出:abc is less than def.
    
  • strncmp(str1, str2, n):比较str1str2的前n个字符,返回值说明同strcmp()。例如:

    const char *str1 = "abcdef";
    const char *str2 = "abcxyz";
    int result = strncmp(str1, str2, 3);
    if (result < 0) {
        printf("%s is less than %s.\n", str1, str2);
    } else if (result > 0) {
        printf("%s is greater than %s.\n", str1, str2);
    } else {
        printf("%s and %s are equal.\n", str1, str2);
    }  // 输出:abcdef and abcxyz are equal.
    
  • strchr(str, ch):在字符串str中查找字符ch首次出现的位置,返回指向该位置的指针;若未找到,返回NULL。例如:

    const char *text = "Find the 'e'.";
    char *found = strchr(text, 'e');
    if (found) {
        printf("Found 'e' at position %td.\n", found - text + 1);  // 输出:Found 'e' at position ¼.
    } else {
        printf("'e' not found.\n");
    }
    
  • strrchr(str, ch):在字符串str中查找字符ch最后一次出现的位置,返回指向该位置的指针;若未找到,返回NULL。例如:

    const char *text = "Find the last 'e'.";
    char *found = strrchr(text, 'e');
    if (found) {
        printf("Found last 'e' at position %td.\n", found - text + 1);  // 输出:Found last 'e' at position 9.
    } else {
        printf("'e' not found.\n");
    }
    
  • strstr(haystack, needle):在字符串haystack中查找子串needle首次出现的位置,返回指向该位置的指针;若未找到,返回NULL。例如:

    const char *haystack = "The quick brown fox jumps over the lazy dog.";
    const char *needle = "fox";
    char *found = strstr(haystack, needle);
    if (found) {
        printf("Found '%s' at position %td.\n", needle, found - haystack + 1);  // 输出:Found 'fox' at position 10.
    } else {
        printf("'%s' not found.\n", needle);
    }
    
    

3.<stdio.h>中的字符输入输出函数

  • getchar():从标准输入(通常是键盘)读取一个字符,并返回该字符。遇到文件结束符(EOF)时返回EOF。例如:

    int input_char = getchar();
    if (input_char != EOF) {
        printf("Read character: %c\n", input_char);
    } else {
        printf("End of input reached.\n");
    }
    
  • putchar(c):向标准输出(通常是屏幕)输出字符c,并返回该字符。若输出失败,返回EOF。例如:

    char output_char = '!';
    int result = putchar(output_char);
    if (result != EOF) {
        printf("Character '%c' successfully output.\n", output_char);
    } else {
        printf("Output error occurred.\n");
    }
    
  • fgetc(stream):类似于getchar(), 但从指定的输入流stream读取一个字符。遇到文件结束符(EOF)时返回EOF。例如:

    FILE *file = fopen("example.txt", "r");
    if (file) {
        int input_char = fgetc(file);
        if (input_char != EOF) {
            printf("Read character from file: %c\n", input_char);
        } else {
            printf("End of file reached.\n");
        }
        fclose(file);
    } else {
        printf("Failed to open file.\n");
    }
    
  • fputc(c, stream):类似于putchar(),但向指定的输出流stream输出字符c。若输出失败,返回EOF。例如:

    FILE *file = fopen("output.txt", "w");
    if (file) {
        int result = fputc('!', file);
        if (result != EOF) {
            printf("Character '!' successfully written to file.\n");
        } else {
            printf("Output error occurred.\n");
        }
        fclose(file);
    } else {
        printf("Failed to open file for writing.\n");
    }
    

非常抱歉,您提醒得对。下面是关于C语言中格式化输入输出函数的详细解释:

4.<stdio.h>中的格式化输出函数

  • printf(format, ...):根据format字符串指定的格式,将可变数量的参数输出到标准输出(如屏幕)。format字符串包含普通文本和格式化说明符(如%d%s%f等),分别对应不同类型的参数。返回值为成功输出的字符数量,出错时返回负值。例如:

    int number = 42;
    float pi = 3.14159;
    const char *message = "Hello, World!";
    
    printf("Number: %d, Pi: %.2f, Message: %s\n", number, pi, message);
    // 输出:Number: 42, Pi: 3.14, Message: Hello, World!
    
  • fprintf(stream, format, ...):类似于printf(),但输出到指定的输出流stream而非标准输出。例如:

    FILE *file = fopen("output.txt", "w");
    if (file) {
        fprintf(file, "Number: %d, Pi: %.2f, Message: %s\n", number, pi, message);
        fclose(file);
    } else {
        printf("Failed to open file for writing.\n");
    }
    
  • sprintf(buffer, format, ...):类似于printf(),但将格式化输出的结果写入到字符数组buffer中,而不是输出到屏幕。返回值为成功写入buffer的字符数量(不包括末尾的'\0'),出错时返回负值,用于封包。例如:

    char output_buffer[100];
    sprintf(output_buffer, "Number: %d, Pi: %.2f, Message: %s\n", number, pi, message);
    printf("Formatted string: %s", output_buffer);
    // 输出:Formatted string: Number: 42, Pi: 3.14, Message: Hello, World!
    
  • snprintf(buffer, size, format, ...):类似于sprintf(),但限制写入buffer的字符数量不超过size(包括末尾的'\0')。如果实际输出长度小于sizebuffer末尾自动添加'\0';如果实际输出长度大于等于sizebuffer末尾可能不添加'\0',且输出可能被截断。返回值为实际需要写入的字符数量(不包括末尾的'\0'),出错时返回负值,用于封包。例如:

    char truncated_buffer[30];
    int required_size = snprintf(truncated_buffer, sizeof(truncated_buffer), "%s is a very long sentence.", message);
    printf("Truncated string: %s\n", truncated_buffer);
    printf("Required size: %d\n", required_size);
    // 输出可能为:
    // Truncated string: Hello, World! is a ve
    // Required size: 33
    

5.<stdio.h>中的格式化输入函数

  • scanf(format, ...):根据format字符串指定的格式,从标准输入(如键盘)读取数据并存储到对应的参数中。format字符串包含普通文本和格式化说明符(如%d%s%f等),分别对应不同类型的参数。返回值为成功读取的参数数量,遇到文件结束符(EOF)或读取错误时返回EOF。例如:

    int number;
    float pi;
    char message[100];
    
    printf("Enter a number, a floating-point number, and a message:\n");
    scanf("%d%f%s", &number, &pi, message);
    printf("Read values: Number: %d, Pi: %.2f, Message: %s\n", number, pi, message);
    
  • fscanf(stream, format, ...):类似于scanf(),但从指定的输入流stream读取数据。例如:

    FILE *file = fopen("input.txt", "r");
    if (file) {
        fscanf(file, "%d%f%s", &number, &pi, message);
        fclose(file);
        printf("Read values from file: Number: %d, Pi: %.2f, Message: %s\n", number, pi, message);
    } else {
        printf("Failed to open file for reading.\n");
    }
    
  • sscanf(str, format, ...):类似于scanf(),但从给定的字符串str读取数据,用于解包。例如:

    const char *input_string = "42 3.14159 Hello, World!";
    sscanf(input_string, "%d%f%s", &number, &pi, message);
    printf("Parsed values from string: Number: %d, Pi: %.2f, Message: %s\n", number, pi, message);
    

以上是对C语言中格式化输入输出函数的详细解释和示例。在使用时,应注意检查返回值以确保操作成功,并根据需要处理可能出现的错误情况。对于用户输入,应做好有效性验证和错误处理,防止安全漏洞(如缓冲区溢出)的发生。

6.字符串切割函数

  • strtok(str, delimiters)(在<string.h>中):根据delimiters指定的分隔符序列,将字符串str切割成多个子串。返回第一个子串的地址,后续调用返回后续子串的地址。在分割过程中,分隔符会被替换为'\0'。例如:

    const char *input = "Split this,string,with commas";
    char *token = strtok(input, ",");
    while (token) {
        printf("Token: %s\n", token);
        token = strtok(NULL, ",");
    }
    // 输出:
    // Token: Split this
    // Token: string
    // Token: with commas
    

当然可以。C语言中的字符串数值转换函数主要用于实现字符串与整数或浮点数之间的相互转换。下面是一些常用的转换函数介绍:

7.字符串转数值

1.整数转换函数

  • atoi(str)(在<stdlib.h>中):将包含十进制整数的字符串str转换为int类型整数。忽略前导空格,遇到非数字字符停止解析。返回转换后的整数值。如果字符串无法完全解析为整数或超出int范围,行为未定义。

    const char *str = "1234";
    int num = atoi(str);
    printf("Converted integer: %d\n", num);  // 输出:Converted integer: 1234
    
  • atol(str)(在<stdlib.h>中):与atoi()类似,但将字符串转换为long类型整数。

  • strtol(str, endptr, base)(在<stdlib.h>中):更通用的整数转换函数,将字符串str转换为long类型整数。参数base(可选)指定进制(如2、8、10、16等),默认为10。endptr(可选)是一个指针,用于接收未解析部分的首地址。如果解析成功,*endptr将指向第一个未被解析的字符;如果endptrNULL,则忽略此功能。

    const char *hex_str = "0xFF";
    char *end;
    long hex_num = strtol(hex_str, &end, 16);
    printf("Converted hexadecimal integer: %ld\n", hex_num);  // 输出:Converted hexadecimal integer: 255
    if (*end == '\0') {
        printf("All characters were parsed successfully.\n");
    } else {
        printf("Some characters were not parsed: '%s'\n", end);
    }
    

2.浮点数转换函数

  • atof(str)(在<stdlib.h>中):将包含十进制浮点数的字符串str转换为double类型浮点数。忽略前导空格,遇到非数字字符或非法浮点数格式停止解析。返回转换后的浮点数值。如果字符串无法完全解析为浮点数或超出double范围,行为未定义。

    const char *flt_str = "3.14159";
    double pi = atof(flt_str);
    printf("Converted float: %.6f\n", pi);  // 输出:Converted float: 3.141590
    
  • strtod(str, endptr)(在<stdlib.h>中):更通用的浮点数转换函数,将字符串str转换为double类型浮点数。endptr(可选)是一个指针,用于接收未解析部分的首地址。如果解析成功,*endptr将指向第一个未被解析的字符;如果endptrNULL,则忽略此功能。

    const char *exponential_str = "1.23e-2";
    char *end;
    double exp_num = strtod(exponential_str, &end);
    printf("Converted exponential float: %.6f\n", exp_num);  // 输出:Converted exponential float: 0.012300
    if (*end == '\0') {
        printf("All characters were parsed successfully.\n");
    } else {
        printf("Some characters were not parsed: '%s'\n", end);
    }
    

8.数值转字符串

1.整数转换函数

  • itoa(value, str, base):将整数value转换为指定基数base(如2、8、10、16等)的字符串,并存放在字符数组str中。此函数不是C标准库的一部分,但在许多编译器(特别是Windows环境下)中作为扩展函数提供。返回值为指向str的指针。注意需要确保str指向的缓冲区足够大以容纳转换后的字符串。

    int num = 255;
    char str[10];
    itoa(num, str, 16);
    printf("Converted integer to hexadecimal string: %s\n", str);  // 输出:Converted integer to hexadecimal string: FF
    
  • snprintf()(在<stdio.h>中):标准C库提供的格式化输出函数,可用于将整数转换为字符串。它可以将格式化的数据写入到字符串中,其中%d%i%u%x等格式说明符分别对应不同类型的整数。需要确保目标字符串有足够的空间存放转换后的结果。

    int num = 12345;
    char str[20];
    snprintf(str, sizeof(str), "%d", num);
    printf("Converted integer to decimal string: %s\n", str);  // 输出:Converted integer to decimal string: 12345
    
    unsigned int unum = .png;
    snprintf(str, sizeof(str), "%x", unum);
    printf("Converted unsigned integer to hexadecimal string: %s\n", str);  // 输出:Converted unsigned integer to hexadecimal string: fff
    

2.浮点数转换函数

  • gcvt(value, ndigit, buf):将浮点数value转换为字符串,并将结果存储在buf指向的缓冲区中。ndigit指定要保留的小数位数。返回值为指向转换后字符串的指针。此函数不是C标准库的一部分,但在某些编译器中可用。

    double pi = 3.14159;
    char buf[20];
    gcvt(pi, .jpg, buf);
    printf("Converted float to string: %s\n", buf);  // 输出:Converted float to string: 3.1416
    
  • ecvt(value, ndigit, decpt, sign):将浮点数value转换为字符串,并返回指向转换后字符串的指针。ndigit指定要保留的有效数字位数(包括小数点前的数字和小数点后的数字)。decptsign是输出参数,分别用于接收小数点相对于字符串起始位置的偏移量(负数表示小数点在字符串之前,正数表示小数点在字符串之中或之后)和符号(0表示正数,非0表示负数)。此函数不是C标准库的一部分,但在某些编译器中可用。

    double pi = 3.14159;
    char *str = ecvt(pi, 4, &decpt, &sign);
    printf("Converted float to string: %s\n", str);  // 输出:Converted float to string: 3.1416
    printf("Decimal point offset: %d\n", decpt);  // 输出:Decimal point offset: 1
    printf("Sign: %d\n", sign);  // 输出:Sign: 0
    
  • fcvt(value, ndigit, decpt, sign):类似于ecvt(), 但只保留小数点后的有效数字位数。返回值和输出参数含义与ecvt()相同。

    double pi = 3.14159;
    char *str = fcvt(pi, 4, &decpt, &sign);
    printf("Converted float to string: %s\n", str);  // 输出:Converted float to string: .1416
    printf("Decimal point offset: %d\n", decpt);  // 输出:Decimal point offset: -1
    printf("Sign: %d\n", sign);  // 输出:Sign: 0
    
  • sprintf() / snprintf()(在<stdio.h>中):标准C库提供的格式化输出函数,也可用于将浮点数转换为字符串。使用%f%e%g等格式说明符来指定浮点数的输出格式。需要确保目标字符串有足够的空间存放转换后的结果。

    double pi = 3.14159;
    char str[20];
    snprintf(str, sizeof(str), "%.4f", pi);
    printf("Converted float to string: %s\n", str);  // 输出:Converted float to string: 3.1416
    

9.sprintf() 高级用法

1. 多个输出项和格式化选项

sprintf() 可以一次处理多个输出项,每个项由相应的格式化说明符和变量指定:

#include <stdio.h>

int main() {
    int a = 123;
    float b = 45.67;
    char c[] = "Hello, World!";
    char formatted[100];

    sprintf(formatted, "%d %f %s", a, b, c);
    printf("%s\n", formatted);  // 输出:123 45.670000 Hello, World!
}

这里使用了 %d(整数)、%f(浮点数)和 %s(字符串)三个不同的格式化说明符。

2. 字符宽度和精度

可以通过在格式化说明符前添加数字来指定输出的最小字符宽度或浮点数的小数位数:

#include <stdio.h>

int main() {
    int number = ½;
    char formatted[50];

    sprintf(formatted, "%5d", number);  // 至少占用5个字符宽度,不足则填充空格
    printf("%s\n", formatted);  // 输出:  123

    sprintf(formatted, "%.2f", 3.14159);  // 浮点数保留两位小数
    printf("%s\n", formatted);  // 输出:3.14
}

3. 对齐与填充字符

使用特定的标志可以控制输出的对齐方式和填充字符:

#include <stdio.h>

int main() {
    int num = 123;
    char formatted[50];

    // 左对齐,用0填充
    sprintf(formatted, "%05d", num);
    printf("%s\n", formatted);  // 输出:00123

    // 右对齐,用空格填充
    sprintf(formatted, "%-5d", num);
    printf("%s\n", formatted);  // 输出:123  
}

4. 长度修饰符

对于不同长度的整数和浮点数类型,可以使用长度修饰符来确保正确的类型匹配:

#include <stdio.h>
#include <inttypes.h>  // 提供 PRIu64 等宏

int main() {
    uint64_t large_number = 1234567890123ULL;
    char formatted[50];

    // 使用长度修饰符PRIu64处理无符号长整数
    sprintf(formatted, "%" PRIu64, large_number);
    printf("%s\n", formatted);  // 输出:1234567890123
}

10.sscanf() 高级用法

1. 多个输入项和格式化选项

sscanf() 可以从同一字符串中按指定格式提取多个输入项:

#include <stdio.h>

int main() {
    char input[] = "123 45.67 Hello, World!";
    int a;
    float b;
    char c[20];

    int items_scanned = sscanf(input, "%d %f %s", &a, &b, c);
    printf("Scanned items: %d\n", items_scanned);
    printf("a = %d, b = %.2f, c = %s\n", a, b, c);
    // 输出:Scanned items: 3
    //       a = 123, b = 45.67, c = Hello, World!
}

2. 字段宽度限制

通过在格式化说明符前指定宽度,可以限制从字符串中读取的字符数量:

#include <stdio.h>

int main() {
    char input[] = "1234567890";
    int number;

    // 仅读取前3个字符
    int result = sscanf(input, "%3d", &number);
    printf("Number: %d\n", number);  // 输出:123
}

3. 忽略某些字段

使用星号 (*) 作为赋值抑制符,可以读取并跳过与格式化说明符匹配的字段,而不将其存储到变量中:

#include <stdio.h>

int main() {
    char input[] = "123 abc 456 def";
    int a, b;

    // 忽略中间的字符串字段
    int items_scanned = sscanf(input, "%d %*s %d", &a, &b);
    printf("Scanned items: %d\n", items_scanned);
    printf("a = %d, b = %d\n", a, b);
    // 输出:Scanned items: 2
    //       a = 123, b = 456
}

9.格式化输入输出表

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

scanf("<格式化字符串>", <参量表>);
格式控制符 说明
%c 读取一个单一的字符
%hd、%d、%ld 读取一个十进制整数,并分别赋值给 short、int、long 类型
%ho、%o、%lo 读取一个八进制整数(可带前缀也可不带),并分别赋值给 short、int、long 类型
%hx、%x、%lx 读取一个十六进制整数(可带前缀也可不带),并分别赋值给 short、int、long 类型
%hu、%u、%lu 读取一个无符号整数,并分别赋值给 unsigned short、unsigned int、unsigned long 类型
%f、%lf 读取一个十进制形式的小数,并分别赋值给 float、double 类型
%e、%le 读取一个指数形式的小数,并分别赋值给 float、double 类型
%g、%lg 既可以读取一个十进制形式的小数,也可以读取一个指数形式的小数,并分别赋值给 float、double 类型
%s 读取一个字符串(以空白符为结束)

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

printf("<格式化字符串>", <参量表>);

format 可以是一个简单的常量字符串,但是您可以分别指定 %s、%d、%c、%f 等来输出或读取字符串、整数、字符或浮点数。还有许多其他可用的格式选项,可以根据需要使用。

格式控制符 说明
%c 输出一个单一的字符
%hd、%d、%ld 以十进制、有符号的形式输出 short、int、long 类型的整数
%hu、%u、%lu 以十进制、无符号的形式输出 short、int、long 类型的整数
%ho、%o、%lo 以八进制、不带前缀、无符号的形式输出 short、int、long 类型的整数
%#ho、%#o、%#lo 以八进制、带前缀、无符号的形式输出 short、int、long 类型的整数
%hx、%x、%lx %hX、%X、%lX 以十六进制、不带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字也小写;如果 X 大写,那么输出的十六进制数字也大写。
%#hx、%#x、%#lx %#hX、%#X、%#lX 以十六进制、带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字和前缀都小写;如果 X 大写,那么输出的十六进制数字和前缀都大写。
%f、%lf 以十进制的形式输出 float、double 类型的小数
%e、%le %E、%lE 以指数的形式输出 float、double 类型的小数。如果 e 小写,那么输出结果中的 e 也小写;如果 E 大写,那么输出结果中的 E 也大写。
%g、%lg %G、%lG 以十进制和指数中较短的形式输出 float、double 类型的小数,并且小数部分的最后不会添加多余的 0。如果 g 小写,那么当以指数形式输出时 e 也小写;如果 G 大写,那么当以指数形式输出时 E 也大写。
%s 输出一个字符串
posted @ 2026-08-09 21:29  littlecamel  阅读(4)  评论(0)    收藏  举报