C 从标准DIN中划分数字和字符串
我想知道是否有可能从标准输入中划分数字和字符。 在我的情况下,我知道文本的大小不是固定的 例如,我想从键盘C 从标准DIN中划分数字和字符串,c,C,我想知道是否有可能从标准输入中划分数字和字符。 在我的情况下,我知道文本的大小不是固定的 例如,我想从键盘读取寄存器A(使用gets()fgets()),使用strcmp通过开关语句选择我所指的情况。 但问题是,当我写入写入寄存器A 0x002时,我必须strcmp字符串写入寄存器A,并且 将值(0x002)写入寄存器。我不能strcmp它,因为值不是固定的。 我给出的输入有时有其他格式(例如初始化、重置等) 我知道使用sscanf我可以提取参数(十六进制),但我不能strcmp它 我应该如何处
读取寄存器A
(使用gets()
fgets()
),使用strcmp
通过开关语句选择我所指的情况。
但问题是,当我写入写入寄存器A 0x002
时,我必须strcmp
字符串写入寄存器A
,并且
将值(0x002)写入寄存器。我不能strcmp
它,因为值不是固定的。
我给出的输入有时有其他格式(例如初始化、重置等)
我知道使用sscanf
我可以提取参数(十六进制),但我不能strcmp
它
我应该如何处理这个问题?基本上,您有一组命令,
读取
,写入
,重置
等等。您的程序必须识别这些命令并相应地执行一些操作
您需要通过逐个读取输入的每个部分并根据用户输入执行命令来解析输入
以下是进行此操作的基本设置:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void clear_stdin()
{
int c;
while((c = fgetc(stdin)) != '\n' && c != EOF)
;
}
int main(int argc, char** argv)
{
char buf[64];
char reg[10];
unsigned int val = 0;
int r = 0;
do{
printf("\nEnter a command: ");
scanf("%s", buf);
if(strcmp(buf, "WRITE") == 0) {
scanf("%s", buf); // read away "REGISTER"
scanf("%s", reg); // read name of REGISTER
r = scanf("%x", &val);
if(r == 1) {
printf("write %i to register %s\n", val, reg);
} else {
scanf("%s", buf);
printf("input is not valid: %s\n", buf);
}
} else if(strcmp(buf, "READ") == 0) {
// TODO
} else if(strcmp(buf, "RESET") == 0) {
// TODO
} else if(strcmp(buf, "exit") == 0) {
break;
} else {
printf("Unknown command: %s\n", buf);
}
clear_stdin();
} while(1);
printf("Bye!\n");
return 0;
}
输出
write 255 to register A
您可以使用
scanf(“%s”,buf)编码>并将buf
传递到而不是scanf(“%x”,&val)
以将十六进制数从字符串转换为长字符串。我建议不惜一切代价避免scanf()
,并使用strtok()
或类似方法:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSIZE 1000
int main(void) {
char buffer[MAXSIZE];
char * token;
int n = 1;
puts("Enter your command:");
if ( fgets(buffer, MAXSIZE, stdin) == NULL ) {
fputs("Error getting input", stderr);
return EXIT_FAILURE;
}
token = strtok(buffer, " ");
while ( token ) {
printf("Token %d is %s\n", n++, token);
token = strtok(NULL, " ");
}
return EXIT_SUCCESS;
}
听起来您想使用类似于strtok()
的方法将字符串解析为不同的组件(在本例中为“写入”、“寄存器”、“A”和“0x002”),然后对其进行处理。换句话说,最好先检查是否有“写入”,如果有,检查它是否是“寄存器”,如果是,检查它是哪个寄存器,然后你就会知道,期望一个数字作为最后的标记。这样,您就不必分别检查“写入寄存器A”,然后再检查“写入寄存器B”,然后再检查“写入其他内容”等等,也不必使用get()
,因为(1)它不好;(2)C11实际上最终摆脱了它,所以它不再是C。请注意,您将无法在strcmp()中使用switch
语句
有两个原因:(1)switch语句中的情况必须是编译时常量,(2)strcmp()的返回值定义得不够好,只有三种状态(小于零、等于零或大于零)“小于”值可以是从-1向下的任意数字,“大于”值可以是从+1向上的任意数字。fflush(stdin)
提供了未定义的行为,fflush()
的行为仅由C标准(和POSIX)定义对于输出和更新流。@PaulGriffiths是的,你是对的,这很快很脏,fflush
应该只用于输出流。为了不传播坏的/错误的内容,我用另一种方法代替了它。谢谢你指出这一点!这种方法也很好,使用fgets
(前提是MAXSIZE足够大)以及将输入标记为其部分。MAXSIZE
在使用fgets()
时总是足够大,以避免非法写入,但是是的,如果有人键入长度超过1000个字符的指令,他们将收到错误消息。从一个邪恶(scanf()
)到另一个邪恶(strtok()
)…在上下文中,strtok()
可能是较小的邪恶,但这不是我推荐的例行程序。主要问题是它践踏了分隔符,因此无法分辨它是什么(如果语言开始使用括号等,这就开始起作用)。@PaulGriffiths使用1000的可能性比使用buf的可能性小[64]
;-)@user2221231:如果答案对你有帮助,你可以接受(即单击复选标记),而不是投票,因为你在这方面有足够的声誉。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSIZE 1000
int main(void) {
char buffer[MAXSIZE];
char * token;
int n = 1;
puts("Enter your command:");
if ( fgets(buffer, MAXSIZE, stdin) == NULL ) {
fputs("Error getting input", stderr);
return EXIT_FAILURE;
}
token = strtok(buffer, " ");
while ( token ) {
printf("Token %d is %s\n", n++, token);
token = strtok(NULL, " ");
}
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSIZE 1000
static long register_a = 0;
static long register_b = 0;
static const char * token_delims = " \r\n\t";
static void inst_write(void);
static void inst_write_register(void);
static void inst_write_register_n(long * p_register);
static void error_quit(const char * msg);
int main(void) {
char buffer[MAXSIZE];
char * token;
/* Get input */
puts("Enter your command:");
if ( fgets(buffer, MAXSIZE, stdin) == NULL ) {
error_quit("couldn't get input");
}
/* Tokenize and parse first token */
token = strtok(buffer, token_delims);
if ( token == NULL ) {
error_quit("no instruction specified");
}
else if ( strcmp(token, "WRITE") == 0 ) {
inst_write();
}
else if ( strcmp(token, "READ") == 0 ) {
/* Check for other instructions like this */
}
else {
error_quit("unrecognized instruction");
}
/* Output register contents */
printf("Register A contains: %ld\n", register_a);
printf("Register B contains: %ld\n", register_b);
return EXIT_SUCCESS;
}
/* Processes a WRITE instruction */
void inst_write(void) {
char * token = strtok(NULL, token_delims);
if ( token == NULL ) {
error_quit("missing WRITE operand");
}
else if ( strcmp(token, "REGISTER") == 0 ) {
inst_write_register();
}
else if ( strcmp(token, "MEMLOC") == 0 ) {
/* Check for other things to which to write */
}
else {
error_quit("unrecognized WRITE operand");
}
}
/* Processes a WRITE REGISTER instruction */
void inst_write_register(void) {
char * token = strtok(NULL, token_delims);
if ( token == NULL ) {
error_quit("missing WRITE REGISTER operand");
}
else if ( strcmp(token, "A") == 0 ) {
inst_write_register_n(®ister_a);
}
else if ( strcmp(token, "B") == 0 ) {
/* Check for other registers to which to write */
inst_write_register_n(®ister_b);
}
else {
error_quit("unrecognized register");
}
}
/* Processes the operand of a WRITE REGISTER [X] instruction, and
* stores it in the appropriate register.
*
* Arguments:
* p_register -- pointer to the register in which to store
*/
void inst_write_register_n(long * p_register) {
char * token = strtok(NULL, token_delims);
if ( token == NULL ) {
error_quit("missing WRITE REGISTER [X] operand");
}
else {
char * endptr;
long n = strtol(token, &endptr, 16);
if ( endptr == token ) {
error_quit("WRITE REGISTER [X] operand should be a hex integer");
}
else {
*p_register = n;
}
}
}
/* General error handler, prints the supplied message and exit()s */
void error_quit(const char * msg) {
fprintf(stderr, "Error: %s\n", msg);
exit(EXIT_FAILURE);
}