关于scanf(“%[^\n]“,m.content);

本文解释了scanf函数如何从键盘读取字符串,以及其使用格式控制符的原理。同时指出scanf可能导致的缓冲区溢出风险,并推荐使用fgets函数以提高安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这句代码的意思是从标准输入(键盘)读取一行字符串,不包括换行符,然后存储到变量 a 中。

scanf 是一个格式化输入函数,它可以根据指定的格式控制符,将输入的字符转换为相应的数据类型,并存储到对应的参数中。

这里的格式控制符是 "%[^\n]",它表示读取一个字符集合,其中包含除了换行符以外的所有字符。

a 是一个输入参数,它应该是一个字符数组或者指针,用来存储读取到的字符串。

注意,这句代码可能存在缓冲区溢出的风险,如果输入的字符串长度超过了 a 的大小,就会造成内存泄漏或者程序崩溃。

为了避免这种情况,建议使用 fgets 函数代替 scanf 函数,或者在格式控制符中指定最大长度,例如 "%99[^\n]" 表示最多读取 99 个字符。

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <conio.h> #define MAX_USERS 100 #define MAX_ARTICLES 200 #define FILENAME_USERS "users.txt" #define FILENAME_ARTICLES "articles.txt" // 角色枚举 typedef enum { ROLE_ADMIN, ROLE_AUTHOR, ROLE_READER } UserRole; // 文章类型枚举 typedef enum { TYPE_POETRY, TYPE_NOVEL, TYPE_FAIRY_TALE } ArticleType; // 用户结构体 typedef struct { char username[50]; char password[50]; UserRole role; char gender; int age; } User; // 文章结构体 typedef struct { char title[100]; char author[50]; char publish_date[20]; ArticleType type; char content[500]; } Article; // 全局变量 User users[MAX_USERS]; Article articles[MAX_ARTICLES]; int userCount = 0; int articleCount = 0; User currentUser; // 当前登录用户 // 函数声明 void loadData(); void saveData(); void registerUser(); int login(); void showUserMenu(); void manageProfile(); void manageArticles(); void publishArticle(); void editArticle(); void viewArticles(); void searchArticle(); void viewMyArticles(); void browseArticles(); void displayArticle(int index); void deleteArticle(); void listAllUsers(); const char *getRoleName(UserRole role) { switch (role) { case ROLE_ADMIN: return "管理员"; case ROLE_AUTHOR: return "作者"; case ROLE_READER: return "读者"; default: return "未知"; } } const char *getArticleTypeName(ArticleType type) { switch (type) { case TYPE_POETRY: return "诗歌"; case TYPE_NOVEL: return "小说"; case TYPE_FAIRY_TALE: return "童话"; default: return "未知"; } } // 加载数据 void loadData() { // 加载用户数据 FILE *userFile = fopen(FILENAME_USERS, "r"); if (userFile) { while (fscanf(userFile, "%49[^|]|%49[^|]|%d|%c|%d\n", users[userCount].username, users[userCount].password, &users[userCount].role, &users[userCount].gender, &users[userCount].age) == 5) { userCount++; } fclose(userFile); } // 加载文章数据 FILE *articleFile = fopen(FILENAME_ARTICLES, "r"); if (articleFile) { while (fscanf(articleFile, "%99[^|]|%49[^|]|%19[^|]|%d|%499[^\n]\n", articles[articleCount].title, articles[articleCount].author, articles[articleCount].publish_date, &articles[articleCount].type, articles[articleCount].content) == 5) { articleCount++; } fclose(articleFile); } } // 保存数据 void saveData() { // 保存用户数据 FILE *userFile = fopen(FILENAME_USERS, "w"); for (int i = 0; i < userCount; i++) { fprintf(userFile, "%s|%s|%d|%c|%d\n", users[i].username, users[i].password, users[i].role, users[i].gender, users[i].age); } fclose(userFile); // 保存文章数据 FILE *articleFile = fopen(FILENAME_ARTICLES, "w"); for (int i = 0; i < articleCount; i++) { fprintf(articleFile, "%s|%s|%s|%d|%s\n", articles[i].title, articles[i].author, articles[i].publish_date, articles[i].type, articles[i].content); } fclose(articleFile); } // 用户注册 void registerUser() { if (userCount >= MAX_USERS) { printf("用户数量已达上限!\n"); return; } User newUser; printf("\n=== 用户注册 ===\n"); printf("请输入用户名: "); scanf("%49s", newUser.username); // 检查用户名是否已存在 for (int i = 0; i < userCount; i++) { if (strcmp(users[i].username, newUser.username) == 0) { printf("用户名已存在!\n"); return; } } printf("请输入密码: "); scanf("%49s", newUser.password); int roleChoice; printf("选择角色 (0-管理员, 1-作者, 2-读者): "); scanf("%d", &roleChoice); newUser.role = (UserRole)roleChoice; printf("性别 (M/F): "); scanf(" %c", &newUser.gender); newUser.gender = toupper(newUser.gender); printf("年龄: "); scanf("%d", &newUser.age); users[userCount++] = newUser; saveData(); printf("注册成功!\n"); } // 用户登录 int login() { char username[50], password[50]; printf("\n=== 用户登录 ===\n"); printf("用户名: "); scanf("%49s", username); printf("密码: "); scanf("%49s", password); for (int i = 0; i < userCount; i++) { if (strcmp(users[i].username, username) == 0 && strcmp(users[i].password, password) == 0) { currentUser = users[i]; printf("登录成功!欢迎 %s (%s)\n", currentUser.username, getRoleName(currentUser.role)); return 1; } } printf("用户名或密码错误!\n"); return 0; } // 修改个人信息 void manageProfile() { printf("\n=== 个人信息管理 ===\n"); printf("当前信息: \n"); printf("用户名: %s\n", currentUser.username); printf("性别: %c\n", currentUser.gender); printf("年龄: %d\n", currentUser.age); int choice; printf("\n1. 修改密码\n2. 修改性别\n3. 修改年龄\n0. 返回\n选择: "); scanf("%d", &choice); switch (choice) { case 1: printf("新密码: "); scanf("%49s", currentUser.password); break; case 2: printf("新性别 (M/F): "); scanf(" %c", &currentUser.gender); currentUser.gender = toupper(currentUser.gender); break; case 3: printf("新年龄: "); scanf("%d", &currentUser.age); break; case 0: return; default: printf("无效选择!\n"); } // 更新全局用户数组 for (int i = 0; i < userCount; i++) { if (strcmp(users[i].username, currentUser.username) == 0) { users[i] = currentUser; break; } } saveData(); printf("信息更新成功!\n"); } // 发布文章 void publishArticle() { if (articleCount >= MAX_ARTICLES) { printf("文章数量已达上限!\n"); return; } Article newArticle; printf("\n=== 发布新文章 ===\n"); printf("标题: "); scanf(" %[^\n]", newArticle.title); // 读取整行 // 检查标题是否已存在 for (int i = 0; i < articleCount; i++) { if (strcmp(articles[i].title, newArticle.title) == 0) { printf("标题已存在!\n"); return; } } strcpy(newArticle.author, currentUser.username); printf("发布日期 (YYYY-MM-DD): "); scanf("%19s", newArticle.publish_date); int typeChoice; printf("类型 (0-诗歌, 1-小说, 2-童话): "); scanf("%d", &typeChoice); newArticle.type = (ArticleType)typeChoice; printf("内容 (不超过500字符): "); getchar(); // 清除缓冲区 fgets(newArticle.content, sizeof(newArticle.content), stdin); newArticle.content[strcspn(newArticle.content, "\n")] = '\0'; // 移除换行符 articles[articleCount++] = newArticle; saveData(); printf("文章发布成功!\n"); } // 编辑文章 void editArticle() { printf("\n=== 编辑文章 ===\n"); viewMyArticles(); if (articleCount == 0) return; int index; printf("输入要编辑的文章编号 (-1取消): "); scanf("%d", &index); if (index < 0 || index >= articleCount) { printf("无效编号!\n"); return; } // 检查权限:作者只能编辑自己的文章,管理员可以编辑所有 if (currentUser.role != ROLE_ADMIN && strcmp(articles[index].author, currentUser.username) != 0) { printf("无权编辑此文章!\n"); return; } Article *art = &articles[index]; printf("\n当前标题: %s\n新标题: ", art->title); getchar(); fgets(art->title, sizeof(art->title), stdin); art->title[strcspn(art->title, "\n")] = '\0'; printf("新内容: "); fgets(art->content, sizeof(art->content), stdin); art->content[strcspn(art->content, "\n")] = '\0'; saveData(); printf("文章修改成功!\n"); } // 浏览文章目录 void browseArticles() { printf("\n=== 文章目录 ===\n"); printf("%-5s %-30s %-15s %-10s %-10s\n", "ID", "标题", "作者", "类型", "发布日期"); for (int i = 0; i < articleCount; i++) { printf("%-5d %-30s %-15s %-10s %-10s\n", i, articles[i].title, articles[i].author, getArticleTypeName(articles[i].type), articles[i].publish_date); } } // 查看文章详情 void displayArticle(int index) { if (index < 0 || index >= articleCount) { printf("无效文章ID!\n"); return; } Article art = articles[index]; printf("\n=== 文章详情 ===\n"); printf("标题: %s\n", art.title); printf("作者: %s\n", art.author); printf("类型: %s\n", getArticleTypeName(art.type)); printf("发布日期: %s\n", art.publish_date); printf("内容:\n%s\n", art.content); } // 搜索文章 void searchArticle() { char title[100]; printf("\n=== 文章搜索 ===\n"); printf("输入文章标题: "); scanf(" %[^\n]", title); int found = 0; for (int i = 0; i < articleCount; i++) { if (strstr(articles[i].title, title) != NULL) { displayArticle(i); found = 1; break; } } if (!found) { printf("未找到相关文章!\n"); } } // 查看我的文章 void viewMyArticles() { printf("\n=== 我的文章 ===\n"); int count = 0; for (int i = 0; i < articleCount; i++) { if (strcmp(articles[i].author, currentUser.username) == 0) { printf("[%d] %s (%s)\n", i, articles[i].title, articles[i].publish_date); count++; } } if (count == 0) { printf("您还没有发布文章!\n"); } } // 删除文章 void deleteArticle() { viewMyArticles(); if (articleCount == 0) return; int index; printf("输入要删除的文章编号 (-1取消): "); scanf("%d", &index); if (index < 0 || index >= articleCount) { printf("无效编号!\n"); return; } // 检查权限 if (currentUser.role != ROLE_ADMIN && strcmp(articles[index].author, currentUser.username) != 0) { printf("无权删除此文章!\n"); return; } // 删除文章 for (int i = index; i < articleCount - 1; i++) { articles[i] = articles[i + 1]; } articleCount--; saveData(); printf("文章删除成功!\n"); } // 列出所有用户(管理员) void listAllUsers() { if (currentUser.role != ROLE_ADMIN) { printf("权限不足!\n"); return; } printf("\n=== 用户列表 ===\n"); printf("%-20s %-10s %-6s %-4s\n", "用户名", "角色", "性别", "年龄"); for (int i = 0; i < userCount; i++) { printf("%-20s %-10s %-6c %-4d\n", users[i].username, getRoleName(users[i].role), users[i].gender, users[i].age); } } // 文章管理菜单 void manageArticles() { int choice; do { printf("\n=== 文章管理 ===\n"); printf("1. 发布文章\n"); printf("2. 编辑文章\n"); printf("3. 查看我的文章\n"); printf("4. 删除文章\n"); printf("0. 返回主菜单\n"); printf("选择: "); scanf("%d", &choice); switch (choice) { case 1: publishArticle(); break; case 2: editArticle(); break; case 3: viewMyArticles(); break; case 4: deleteArticle(); break; case 0: break; default: printf("无效选择!\n"); } } while (choice != 0); } // 主菜单 void mainMenu() { int choice; do { printf("\n=== 主菜单 ===\n"); printf("1. 浏览文章\n"); printf("2. 搜索文章\n"); if (currentUser.role == ROLE_ADMIN || currentUser.role == ROLE_AUTHOR) { printf("3. 文章管理\n"); } printf("4. 个人信息管理\n"); if (currentUser.role == ROLE_ADMIN) { printf("5. 用户管理\n"); } printf("0. 退出系统\n"); printf("选择: "); scanf("%d", &choice); switch (choice) { case 1: browseArticles(); break; case 2: searchArticle(); break; case 3: if (currentUser.role == ROLE_ADMIN || currentUser.role == ROLE_AUTHOR) { manageArticles(); } else { printf("权限不足!\n"); } break; case 4: manageProfile(); break; case 5: if (currentUser.role == ROLE_ADMIN) { listAllUsers(); } else { printf("权限不足!\n"); } break; case 0: printf("感谢使用!\n"); exit(0); default: printf("无效选择!\n"); } } while (1); } // 用户菜单 void showUserMenu() { int choice; do { printf("\n=== 主界面 ===\n"); printf("1. 登录\n"); printf("2. 注册\n"); printf("0. 退出\n"); printf("选择: "); scanf("%d", &choice); switch (choice) { case 1: if (login()) { mainMenu(); } break; case 2: registerUser(); break; case 0: printf("感谢使用!\n"); exit(0); default: printf("无效选择!\n"); } } while (1); } int main() { loadData(); showUserMenu(); return 0; } 浏览文章可以查看文章详情
06-27
/* generate_exam.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "dirent.h" #define MAX 1024 #define MAX_Q 5000 #define BUF 4096 typedef struct { int type; /* 0=单选 1=多选 2=判断 */ char stem[1024]; char opts[1024]; char ans[64]; } Question; Question q[MAX_Q]; int q_cnt = 0; /* 去掉行尾 \r\n */ void trim(char* s) { size_t l = strlen(s); while (l && (s[l - 1] == '\r' || s[l - 1] == '\n')) s[--l] = 0; } /* 解析一行 */ void parse_line(char* line) { char* t = strstr(line, "【类型】"); if (!t) return; char* s = strstr(line, "【题干】"); char* o = strstr(line, "【选项】"); char* a = strstr(line, "【答案】"); if (!s || !a) return; /* 题型 */ if (strstr(t, "单选题")) q[q_cnt].type = 0; else if (strstr(t, "多选题")) q[q_cnt].type = 1; else if (strstr(t, "判断题")) q[q_cnt].type = 2; /* 题干 */ *s = 0; strcpy(q[q_cnt].stem, s + strlen("【题干】")); /* 选项 */ *a = 0; if (o) strcpy(q[q_cnt].opts, o + strlen("【选项】")); /* 答案 */ strcpy(q[q_cnt].ans, a + strlen("【答案】")); q_cnt++; } /* 根据题型抽取并写入 XML */ void write_docx_xml(const char* dir, int n0, int n1, int n2) { char path[256]; sprintf(path, "%s/word/document.xml", dir); FILE* fp = fopen(path, "w"); if (!fp) { perror("fopen"); return; } fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "<w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">" "<w:body>"); /* 单选 */ fprintf(fp, "<w:p><w:r><w:t>一、单选题</w:t></w:r></w:p>"); int used[MAX_Q] = { 0 }, cnt = 0; srand((unsigned)time(NULL)); while (cnt < n0) { int i = rand() % q_cnt; if (used[i] || q[i].type != 0) continue; used[i] = 1; fprintf(fp, "<w:p><w:r><w:t>%d. %s</w:t></w:r></w:p>" "<w:p><w:r><w:t>%s</w:t></w:r></w:p>", ++cnt, q[i].stem, q[i].opts); } /* 多选 */ cnt = 0; fprintf(fp, "<w:p><w:r><w:t>二、多选题</w:t></w:r></w:p>"); while (cnt < n1) { int i = rand() % q_cnt; if (used[i] || q[i].type != 1) continue; used[i] = 1; fprintf(fp, "<w:p><w:r><w:t>%d. %s</w:t></w:r></w:p>" "<w:p><w:r><w:t>%s</w:t></w:r></w:p>", ++cnt, q[i].stem, q[i].opts); } /* 判断 */ cnt = 0; fprintf(fp, "<w:p><w:r><w:t>三、判断题</w:t></w:r></w:p>"); while (cnt < n2) { int i = rand() % q_cnt; if (used[i] || q[i].type != 2) continue; used[i] = 1; fprintf(fp, "<w:p><w:r><w:t>%d. %s</w:t></w:r></w:p>", ++cnt, q[i].stem); } fprintf(fp, "</w:body></w:document>"); fclose(fp); } /* 答案 XML */ void write_answer_xml(const char* dir) { char path[256]; sprintf(path, "%s/word/document.xml", dir); FILE* fp = fopen(path, "w"); if (!fp) { perror("fopen"); return; } fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "<w:document><w:body>"); for (int i = 0; i < q_cnt; i++) fprintf(fp, "<w:p><w:r><w:t>%d. %s</w:t></w:r></w:p>", i + 1, q[i].ans); fprintf(fp, "</w:body></w:document>"); fclose(fp); } /* 生成文件夹后 zip 为 docx */ void zip_docx(const char* dir, const char* out) { char cmd[512]; sprintf(cmd, "powershell Compress-Archive -Path \"%s\\*\" -DestinationPath \"%s\" -Force", dir, out); system(cmd); } int load_bank(const char* path) { FILE* fp = fopen(path, "r"); if (!fp) return 0; /* 解析题库逻辑... */ fclose(fp); return 1; } int main() { if (!load_bank("bank.txt")) return 1; int n0, n1, n2; printf("单选题数量:"); (void)scanf("%d", &n0); system("mkdir exam_tmp"); printf("多选题数量:"); (void)scanf("%d", &n1); system("mkdir exam_tmp"); printf("判断题数量:"); (void)scanf("%d", &n2); system("mkdir exam_tmp"); /* 创建临时文件夹并写入 XML */ system("mkdir exam_tmp\\word 2>nul"); system("mkdir answer_tmp\\word 2>nul"); write_docx_xml("exam_tmp", n0, n1, n2); write_answer_xml("answer_tmp"); /* 打包为 docx */ zip_docx("exam_tmp", "exam.docx"); zip_docx("answer_tmp", "answer.docx"); printf("已生成 exam.docx / answer.docx\n"); system("rmdir /s /q exam_tmp answer_tmp 2>nul"); return 0; }
最新发布
07-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值