- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在使用 scanf()
时遇到问题。我从阅读论坛之类的地方知道 scanf()
在 C 中有很多问题,但我只是还在学习基础知识,所以我不知道所有的细节。
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
struct Biodata {
char name[21],
address[65],
date[11],
phone[17];
};
int main() {
struct Biodata bio[10];
int input_max = 0,
index_struct = 0;
while (printf("Input the amount of data! ") && scanf("%[0-9]*d", &input_max) < 1) {
printf("Error! Please, try again!\n\n");
fflush(stdin);
}
for (index_struct = 1; index_struct <= input_max; index_struct++) {
printf("Your input data count is %d.\n", input_max);
printf("Data %d.\n", index_struct);
fflush(stdin);
while (printf("Name\t: ") && scanf("%[A-Z a-z]s", &bio[index_struct].name) < 1) {
printf("Error! Please, try again!\n\n");
fflush(stdin);
}
fflush(stdin);
while (printf("Address\t: ") && scanf("%[^\n]s", &bio[index_struct].address) < 1) {
printf("Error! Please, try again!\n\n");
fflush(stdin);
}
fflush(stdin);
while (printf("Birthdate\t: (YYYY/MM/DD)\n") && scanf("%[^\n A-Z a-z]s", &bio[index_struct].date) < 1) {
printf("Error! Please, try again!\n\n");
fflush(stdin);
}
fflush(stdin);
while (printf("Phone Number\t: ") && scanf("%[^\n A-Z a-z]s", &bio[index_struct].phone) < 1) {
printf("Error! Please, try again!\n\n");
fflush(stdin);
}
fflush(stdin);
printf("\n");
}
printf("Input the index number you'd like the data to be pulled from! ");
scanf("%d", &index_struct);
printf("%-10s\n%-64s\n%-10s\n%-16s",
bio[index_struct].name, bio[index_struct].address,
bio[index_struct].date, bio[index_struct].phone);
return 0;
}
当输入是空格时,我试图让每个输入都能够输出错误。 [^\n]
或 [A-Z]
或 [0-9]
的扫描集通常在更简单的情况下对我有帮助。但是,在这一个中,当我在 input_max
for
while (printf("Input the amount of data! ") && scanf("%[0-9]*d", &input_max) < 1) {
printf("Error! Please, try again!\n\n");
fflush(stdin);
}
input_max
给出的数字与给定的数字不同。这里发生了什么?我该怎么做才能避开它?
我也不完全理解这段代码是如何作为错误输出工作的,因为我在网上的某个地方发现了这一点。
编辑:正如@JonathanLeffler 所建议的,scanf()
将我的输入作为 ASCII、ISO 8859-x 或 Unicode 或所有格式的代码点他们中的。但是,当我删除扫描集并将其转换为 scanf(%d, &input_max)
时,输入保持原样。但是,我确实需要扫描集,这样我就可以输入一个空格,并在 scanf()
中输入一个空格时弹出我设置的错误消息。
最佳答案
你误会了 [
成为 %s
的修饰符和 %d
-例如。 %3d
- 它不是。 %[
本身是一个转换说明符,工作方式类似于 %s
.
因此,正如@user3629249 在评论中指出的那样,s
和 d
在 %[
的末尾说明符(例如在 %[^\n A-Z a-z]s
中)是无关紧要的。还有 %[
中的空格事情。所以%[A-z a-z]
不同于%[A-Za-z]
让我们看看在打开格式警告的情况下进行编译时遇到的问题。 (-Wformat,如果您使用的是 gcc 或 clang),您将得到如下内容:
foo.c:19:68: warning: format specifies type 'char *' but the argument has type 'int *' [-Wformat]
while (printf("Input the amount of data! ") && scanf("%[0-9]*d", &input_max)<1) {
~~~~~ ^~~~~~~~~~
%d
foo.c:29:55: warning: format specifies type 'char *' but the argument has type 'char (*)[21]' [-Wformat]
while (printf("Name\t: ") && scanf("%[A-Z a-z]s", &bio[index_struct].name)<1) {
~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~
foo.c:34:54: warning: format specifies type 'char *' but the argument has type 'char (*)[65]' [-Wformat]
while (printf("Address\t: ") && scanf("%[^\n]s", &bio[index_struct].address)<1) {
~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~
foo.c:39:78: warning: format specifies type 'char *' but the argument has type 'char (*)[11]' [-Wformat]
while (printf("Birthdate\t: (YYYY/MM/DD)\n") && scanf("%[^\n A-Z a-z]s", &bio[index_struct].date)<1) {
~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~
foo.c:44:67: warning: format specifies type 'char *' but the argument has type 'char (*)[17]' [-Wformat]
while (printf("Phone Number\t: ") && scanf("%[^\n A-Z a-z]s", &bio[index_struct].phone)<1) {
~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~
您的代码还有其他问题:
index_struct
for 循环)但是它被声明为大小为 10 的数组 Biodata bio[10];
在 C 中数组是 0
基于,所以它们来自 0
至 size-1
并且你的for-loop会遇到段错误,因为bio[10]
将是未定义的。
您要求的是 input_max
在您的 for 循环中,但您需要它用于 for 循环。
如果 input_max 大于 bio
的声明大小会发生什么数组?
其他一些值得考虑的好事:
printf 是用于报告错误的糟糕函数,错误应该转到 stderr,而不是 stdout,因此最好使用 fprintf 并指定 stderr。
既然您有兴趣确保正确解析输入,为什么不创建自己的解析器而不是使用 scanf?
你强制重新提示错误,让我们把它分解成它自己的函数。
我的 C 风格与你的有点不同,我有我的理由 :-),既然这只是个人意见,那我们就按照我的来吧。
struct biodata {
char name[21]; /* format: FirstName LastName */
char address[65]; /* format: Free-form upto 65 chars */
char birthday[11]; /* format: YYYY/MM/DD */
char phone[17]; /* format: up to digits or a spaces */
};
下面是一组匹配函数,它接收输入行并告诉我们该行是否完全符合我们的预期。如果是,则返回 true,否则返回 false。您将需要 #include <stdbool.h>
为此。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
struct biodata {
char name[21]; /* format: FirstName LastName */
char address[65]; /* format: Free-form upto 65 chars */
char birthday[11]; /* format: YYYY/MM/DD */
char phone[17]; /* format: up to digits or a spaces */
};
bool match_name(const char *line)
{
char tmp[128];
return line!=NULL
&& sscanf(line, "%128[A-Za-z]%128[ ]%128[A-Za-z]", tmp, tmp, tmp) == 3
&& strlen(tmp) < 21;
}
bool match_address(const char *line)
{
return line != NULL
&& strlen(line) > 5
&& strlen(line) < 65; /* no format check here, maybe later */
}
bool match_telephone(const char *line)
{
char tmp[128];
return line /* notice the alternate form of checking line!=NULL */
&& sscanf(line, "%128[0-9 ]", tmp)==1
&& strlen(tmp) < 17;
}
/* here we'll use strptime to see if our line is a valid date */
bool match_birthday(const char *line)
{
struct tm tm; /* time structure */
if(!line)
return false;
return strptime(line, "%Y/%m/%d", &tm) != NULL;
}
char * ask(const char *prompt, char *line, size_t maxlen)
{
printf("%-30s:", prompt);
fflush(stdout);
fgets(line, maxlen, stdin);
return line; /* we return the pointer for ease of use */
}
/* a test function */
void test_matchers() {
char line[256];
/* remember ask returns our line so we are able to pass it to our matchers */
while(!match_name(ask("Name (first last)", line, sizeof(line))))
;
while(!match_address(ask("Address (at least 5 chars)", line, sizeof(line))))
;
while(!match_birthday(ask("Birthday (YYYY/MM/DD)", line, sizeof(line))))
;
while(!match_telephone(ask("Telephone (max 16 digits)", line, sizeof(line))))
;
}
int main()
{
test_matchers();
return 0;
}
测试一下。
$ ./bar
Name (first last) :Ahmed Masud
Address (at least 5 chars) :1999 Somewhere Out there, Bingo, Bongo, 10002, USA
Birthday (YYYY/MM/DD) :1970/01/10
Telephone (max 16 digits) :1-201-555-1212
现在让我们以合理的方式将东西复制到我们的结构中
/* add a function to print a biodata */
void print_bio(const struct biodata *bio)
{
printf("***** bio data *****\n"
"Name: %-10s\nAddress: %-64s\nBirthday: %-10s\nPhone: %-16s\n",
bio->name, bio->address,
bio->birthday, bio->phone);
}
注意大部分像test_matches
.除了我们添加了复制行到适当的字段
int main()
{
char line[256];
struct biodata bio;
while(!match_name(ask("Name (first last)", line, sizeof(line))))
;
strncpy(bio.name, line, sizeof(bio.name));
while(!match_address(ask("Address (at least 5 chars)", line, sizeof(line))))
;
strncpy(bio.address, line, sizeof(bio.address));
while(!match_birthday(ask("Birthday (YYYY/MM/DD)", line, sizeof(line))))
;
strncpy(bio.birthday, line, sizeof(bio.birthday));
while(!match_telephone(ask("Telephone (max 16 digits)", line, sizeof(line))))
;
strncpy(bio.phone, line, sizeof(bio.phone));
print_bio(&bio);
return 0;
}
好吧,我们可以提示用户并将内容放入我们的结构中,但是在 main 中执行它很笨重,所以让我们将其放入自己的函数中。
int get_bio(struct biodata *bio)
{
char line[256];
while(!match_name(ask("Name (first last)", line, sizeof(line))))
;
strncpy(bio->name, line, sizeof(bio->name));
while(!match_address(ask("Address (at least 5 chars)", line, sizeof(line))))
;
strncpy(bio->address, line, sizeof(bio->address));
while(!match_birthday(ask("Birthday (YYYY/MM/DD)", line, sizeof(line))))
;
strncpy(bio->birthday, line, sizeof(bio->birthday));
while(!match_telephone(ask("Telephone (max 16 digits)", line, sizeof(line))))
;
strncpy(bio->phone, line, sizeof(bio->phone));
return 0;
}
int main()
{
struct biodata bio[3]; /* let's get 3 records */
int i;
/* bio is made up of a bunch of struct biodata's so we divide its size by sizeof the struct biodata to get how many (in our case 3) */
for(i = 0; i < sizeof(bio)/sizeof(struct biodata); i++)
{
printf("\n\nEnter record number: %d\n", 1+i); /* why 1+i here ? :) */
get_bio(&bio[i]);
}
for(i=0; i < sizeof(bio)/sizeof(struct biodata); i++)
{
print_bio(&bio[i]);
}
return 0;
}
我将把其余的功能留作练习。
与此同时,我希望您考虑一下我们开发它的方式。从最里面的功能开始,慢慢向外移动。
像拼乐高积木一样分解问题,首先处理内部零件,测试它们是否完全按照您的要求进行操作,然后围绕它们慢慢构建。
显然,匹配器应该在开发 ask 之前单独开发和测试。我留给你来分解它。
关于c - scanf ("%[^\n]d", x) 或 scanf ("%[0-9]d", x) 将 1 变为 49 并将 2 变为 50,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55252794/
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and th
我试图用这种形式简单地获取数字 28 integer+space+integer+integer+space+integer我试过这个正则表达式 \\s\\d\\d\\s 但我得到了两个数字11 和
最近一直在学习D语言。我一直对运行时感到困惑。 从我能收集到的关于它的信息中,(这不是很多)我知道它是一种有助于 D 的一些特性的运行时。像垃圾收集一样,它与您自己的程序一起运行。但是既然 D 是编译
想问一下这两个正则表达式有区别吗? \d\d\d 与 \d{3} 我已经在我的本地机器上使用 Java 和 Windows 操作系统对此进行了测试,两者都工作正常并且结果相同。但是,当在 linux
我正在学习 Go,而且我坚持使用 Go 之旅(exercise-stringer.go:https://tour.golang.org/methods/7)。 这是一些代码: type IPAddr
我在Java正则表达式中发现了一段令我困惑的代码: Pattern.compile( "J.*\\d[0-35-9]-\\d\\d-\\d\\d" ); 要编译的字符串是: String string
我在 ruby 代码上偶然发现了这个。我知道\d{4})\/(\d\d)\/(\d\d)\/(.*)/是什么意思,但是\1-\2-\3-\4 是什么意思? 最佳答案 \1-\2-\3-\4 是 b
我一直在努力解决这个问题,这让我很恼火。我了解 D 运行时库。它是什么,它做什么。我也明白你可以在没有它的情况下编译 D 应用程序。就像 XoMB 所做的那样。好吧,XoMB 定义了自己的运行时,但是
我有两个列表列表,子列表代表路径。我想找到所有路径。 List> pathList1 List> pathList2 当然是天真的解决方案: List> result = new ArrayList>
我需要使用 Regex 格式化一个字符串,该字符串包含数字、字母 a-z 和 A-Z,同时还包含破折号和空格。 从用户输入我有02-219 8 53 24 输出应该是022 198 53 24 我正在
目标是达到与this C++ example相同的效果: 避免创建临时文件。我曾尝试将 C++ 示例翻译为 D,但没有成功。我也尝试过不同的方法。 import std.datetime : benc
tl;dr:你好吗perfect forwarding在 D? 该链接有一个很好的解释,但例如,假设我有这个方法: void foo(T)(in int a, out int b, ref int c
有什么方法可以在 D 中使用abstract auto 函数吗? 如果我声明一个类如下: class MyClass { abstract auto foo(); } 我收到以下错误: mai
有没有人为内存中重叠的数组切片实现交集?算法在没有重叠时返回 []。 当 pretty-print (使用重叠缩进)内存中重叠的数组切片时,我想要这个。 最佳答案 如果您确定它们是数组,那么只需取 p
我已经开始学习 D,但我在使用 Andrei Alexandrescu 所著的 The D Programming Language 一书中提供的示例时遇到了一些麻烦。由于 int 和 ulong 类
如何创建一个不可变的类? 我的目标是创建一个实例始终不可变的类。现在我只是用不可变的方法和构造函数创建了一个“可变”类。我将其称为 mData,m 表示可变。然后我创建一个别名 alias immut
不久前我买了《The D Programming Language》。好书,很有教育意义。但是,我在尝试编译书中列出的语言功能时遇到了麻烦:扩展函数。 在这本书中,Andrei 写了任何可以像这样调用
我在 D http://www.digitalmars.com/d/2.0/lazy-evaluation.html 中找到了函数参数的惰性求值示例 我想知道如何在 D 中实现可能的无限数据结构,就像
这个问题在这里已经有了答案: 12 年前关闭。 Possible Duplicate: Could anyone explain these undefined behaviors (i = i++
当前是否可以跨模块扫描/查询/迭代具有某些属性的所有函数(或类)? 例如: source/packageA/something.d: @sillyWalk(10) void doSomething()
我是一名优秀的程序员,十分优秀!