鱼C论坛

 找回密码
 立即注册
123
返回列表 发新帖
楼主: bgc1314159

[已解决]复合字面量

[复制链接]
 楼主| 发表于 昨天 19:45 From FishC Mobile | 显示全部楼层
FishC 发表于 2025-11-21 19:11
# fgets 和 gets 对换行符的处理区别

## 核心区别

fgets输入字符数大于参数n
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 19:47 | 显示全部楼层
bgc1314159 发表于 2025-11-21 19:45
FishC 发表于 2025-11-21 19:11
# fgets 和 gets 对 ...


# fgets 输入字符数大于参数 n 的处理

当使用 `fgets` 函数时,如果输入的字符数(包括换行符)大于指定的参数 n,`fgets` 会有特定的处理方式。

## fgets 的基本行为

  1. char *fgets(char *str, int n, FILE *stream);
复制代码


- 最多读取 **n-1** 个字符
- 自动在末尾添加空字符 `\0`
- 保留换行符(如果读取到)

## 输入超过限制时的处理

  1. #include <stdio.h>
  2. #include <string.h>

  3. int main() {
  4.     char buffer[10]; // 只能容纳9个字符 + 空字符
  5.    
  6.     printf("请输入超过9个字符的文本: ");
  7.     fgets(buffer, sizeof(buffer), stdin);
  8.    
  9.     printf("实际读取的内容: %s\n", buffer);
  10.     printf("字符串长度: %zu\n", strlen(buffer));
  11.    
  12.     // 检查是否包含换行符
  13.     if (strchr(buffer, '\n') == NULL) {
  14.         printf("注意: 输入被截断,未包含完整换行符\n");
  15.         
  16.         // 清空输入缓冲区中的剩余字符
  17.         int c;
  18.         while ((c = getchar()) != '\n' && c != EOF);
  19.     } else {
  20.         printf("输入完整,包含换行符\n");
  21.     }
  22.    
  23.     return 0;
  24. }
复制代码


## 详细示例

  1. #include <stdio.h>
  2. #include <string.h>

  3. void demonstrate_fgets_behavior() {
  4.     char small_buffer[6]; // 只能存5个字符 + \0
  5.    
  6.     printf("缓冲区大小: 6 字节 (5字符 + 空字符)\n");
  7.     printf("请输入 'abcdefghij' 进行测试: ");
  8.    
  9.     fgets(small_buffer, sizeof(small_buffer), stdin);
  10.    
  11.     printf("读取的结果: ");
  12.     for(int i = 0; i < sizeof(small_buffer); i++) {
  13.         if(small_buffer[i] == '\0') {
  14.             printf("\\0");
  15.         } else if(small_buffer[i] == '\n') {
  16.             printf("\\n");
  17.         } else {
  18.             printf("%c", small_buffer[i]);
  19.         }
  20.         printf(" ");
  21.     }
  22.     printf("\n");
  23.    
  24.     printf("字符串内容: '%s'\n", small_buffer);
  25.     printf("实际长度: %zu\n", strlen(small_buffer));
  26. }

  27. int main() {
  28.     demonstrate_fgets_behavior();
  29.     return 0;
  30. }
复制代码


**输出示例:**
  1. 缓冲区大小: 6 字节 (5字符 + 空字符)
  2. 请输入 'abcdefghij' 进行测试: abcdefghij
  3. 读取的结果: a b c d e \0
  4. 字符串内容: 'abcde'
  5. 实际长度: 5
复制代码


## 重要特性

### 1. 安全截断
  1. #include <stdio.h>
  2. #include <string.h>

  3. int main() {
  4.     char buf[8];
  5.    
  6.     printf("测试截断: ");
  7.     fgets(buf, sizeof(buf), stdin);
  8.    
  9.     // 检查是否被截断
  10.     if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf)-2] != '\n') {
  11.         printf("输入被截断!\n");
  12.         
  13.         // 清空输入缓冲区
  14.         int ch;
  15.         while ((ch = getchar()) != '\n' && ch != EOF);
  16.     }
  17.    
  18.     return 0;
  19. }
复制代码


### 2. 处理长输入的实用函数
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>

  4. // 安全的输入函数,处理任意长度的输入
  5. char* safe_input() {
  6.     char buffer[100];
  7.     char *result = NULL;
  8.     size_t total_len = 0;
  9.    
  10.     printf("请输入任意长度文本: ");
  11.    
  12.     while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
  13.         size_t chunk_len = strlen(buffer);
  14.         char *new_result = realloc(result, total_len + chunk_len + 1);
  15.         
  16.         if (new_result == NULL) {
  17.             free(result);
  18.             return NULL;
  19.         }
  20.         
  21.         result = new_result;
  22.         strcpy(result + total_len, buffer);
  23.         total_len += chunk_len;
  24.         
  25.         // 如果读取到换行符,说明输入完成
  26.         if (buffer[chunk_len - 1] == '\n') {
  27.             break;
  28.         }
  29.     }
  30.    
  31.     return result;
  32. }

  33. int main() {
  34.     char *input = safe_input();
  35.     if (input != NULL) {
  36.         printf("你输入了: %s", input);
  37.         free(input);
  38.     }
  39.    
  40.     return 0;
  41. }
复制代码


## 关键要点

1. **安全保证**:`fgets` 永远不会写入超过 n 个字符到缓冲区
2. **截断行为**:当输入超过限制时,只读取前 n-1 个字符
3. **换行符处理**:
   - 如果在 n-1 个字符内遇到换行符,会包含在结果中
   - 如果输入被截断,可能不包含换行符
4. **缓冲区清理**:被截断时需要手动清理输入缓冲区中的剩余字符

## 与危险函数的对比

  1. // 危险的 gets - 可能导致缓冲区溢出
  2. // char buffer[10];
  3. // gets(buffer); // 如果输入超过9个字符,程序可能崩溃

  4. // 安全的 fgets - 保证不会溢出
  5. char buffer[10];
  6. fgets(buffer, sizeof(buffer), stdin); // 最多读取9个字符
复制代码


**总结:** `fgets` 在输入超过限制时会安全地截断输入,这是它比 `gets` 安全的重要原因。使用时需要检查是否发生了截断,并相应处理输入缓冲区。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 20:30 From FishC Mobile | 显示全部楼层
FishC 发表于 2025-11-21 19:47
# fgets 输入字符数大于参数 n 的处理

当使用 `fgets` 函数时,如果输入的字符数(包括换行符)大于 ...

gets_s在读取到最大字符数还没见到换行符
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 20:31 | 显示全部楼层
bgc1314159 发表于 2025-11-21 20:30
FishC 发表于 2025-11-21 19:47
# fgets 输入字符数 ...


# gets_s 函数在读取到最大字符数仍未遇到换行符的处理

`gets_s` 是 C11 标准中引入的安全版本,用于替代不安全的 `gets` 函数。当它读取到最大字符数但仍未遇到换行符时,会有特定的处理方式。

## gets_s 函数原型

  1. char *gets_s(char *str, rsize_t n);
复制代码


## 输入超过限制时的行为

当 `gets_s` 读取到 `n-1` 个字符仍未遇到换行符时:

1. **终止读取**:立即停止读取更多字符
2. **清空缓冲区**:将目标字符串的第一个字符设为空字符 `\0`
3. **调用约束处理函数**:触发运行时约束违规处理
4. **可能终止程序**:根据约束处理函数的设置,程序可能被终止

## 示例代码

#include <stdio.h>
#include <stdlib.h>

int main() {
    char buffer[6]; // 最多存储5个字符 + \0
   
    printf("请输入超过5个字符的文本: ");
   
    // 使用 gets_s
    if (gets_s(buffer, sizeof(buffer)) == NULL) {
        printf("gets_s 检测到错误,输入被截断\n");
        printf("当前缓冲区内容: '%s'\n", buffer);
        
        // 注意:在某些实现中,程序可能在此处终止
    } else {
        printf("成功读取: %s\n", buffer);
    }
   
    return 0;
}

## 与 fgets 的对比

#include <stdio.h>
#include <string.h>

void compare_functions() {
    char buf1[6], buf2[6];
   
    printf("=== fgets 行为 ===\n");
    printf("输入超过5个字符: ");
    fgets(buf1, sizeof(buf1), stdin);
    printf("fgets 结果: '%s' (长度: %zu)\n", buf1, strlen(buf1));
   
    // 清空输入缓冲区
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
   
    printf("\n=== gets_s 行为 ===\n");
    printf("输入超过5个字符: ");
   
    // 注意:实际运行效果取决于编译器实现
    if (gets_s(buf2, sizeof(buf2)) == NULL) {
        printf("gets_s 检测到约束违规\n");
        printf("缓冲区被清空: '%s'\n", buf2);
    } else {
        printf("gets_s 结果: '%s'\n", buf2);
    }
}

int main() {
    compare_functions();
    return 0;
}

## 重要注意事项

### 1. 编译器支持
- `gets_s` 是 C11 可选特性,并非所有编译器都支持
- GCC 默认不支持,需要特定标志
- MSVC 支持较好

### 2. 可移植性问题
由于 `gets_s` 的支持不一致,更推荐使用 `fgets`:

#include <stdio.h>
#include <string.h>

void safe_input(char *buffer, size_t size) {
    if (fgets(buffer, size, stdin) != NULL) {
        // 移除换行符
        char *newline = strchr(buffer, '\n');
        if (newline != NULL) {
            *newline = '\0';
        } else {
            // 输入被截断,清空缓冲区
            int c;
            while ((c = getchar()) != '\n' && c != EOF);
            printf("警告: 输入被截断\n");
        }
    }
}

int main() {
    char buffer[6];
   
    printf("安全输入示例: ");
    safe_input(buffer, sizeof(buffer));
    printf("读取结果: '%s'\n", buffer);
   
    return 0;
}

## 总结

- **gets_s**:读取到最大字符数未遇换行符时,会清空缓冲区并可能终止程序
- **fgets**:读取到最大字符数未遇换行符时,会安全截断并继续运行
- **推荐**:由于 `gets_s` 的兼容性问题,建议使用 `fgets` 配合适当的错误处理

**最佳实践**:在需要安全输入时,优先使用 `fgets` 并自行处理换行符和截断情况,这样可以获得更好的可移植性和控制性。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-11-22 02:23

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表