strtok:如何将令牌存储在两个不同的缓冲区中
strtok: How to store tokens in two different buffers
我有一个包含数据类型和变量地址的字符串。这些值由“///”分隔,并且它们是交替的(类型 /// 地址 /// 类型 /// 地址 ...)。这些元组的数量不是固定的,并且会因执行而异。
现在我的问题是如何在循环中处理字符串,因为strtok需要先用原始字符串调用,然后用NULL参数调用,但在循环中它必须调用两次。因此,在第一个循环之后,strtok 被调用了三次,这导致 strtok 执行的计数不均匀,而它应该是偶数。我试图通过在循环外处理第一个元组(因为必须使用原始字符串调用 strtok)并在循环内处理其余元组来解决这个问题。
char mystring[128];
char seperator[] = "///";
char *part;
int type [128];
int address [128];
number_of_variables = 0;
part = strtok(mystring, seperator);
type[number_of_variables] = (int) atoi(part);
part = strtok(NULL, seperator);
address[number_of_variables] = (int)strtol(part, NULL, 16);
while(part != NULL){
part = strtok(NULL, seperator);
type[number_of_variables] = (int) atoi(part);
part = strtok(NULL, seperator);
address[number_of_variables] = (int)strtol(part, NULL, 16);
number_of_variables++;
}
所以现在我的 strtok 执行次数是偶数,但是如果我的字符串包含例如 2 个元组,它将第二次进入循环,因此第五次调用 strtok,这会导致程序崩溃,因为 atoi( ) 得到一个错误的指针。
编辑:
mystring 的示例:
"1///0x37660///2///0x38398"
1 和 2 是进一步程序的类型标识符。
我可以建议以下循环,如下面的演示程序所示。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char mystring[128] = "1///0x37660///2///0x38398";
char separator[] = "/ ";
int type [128];
int address [128];
size_t number_of_variables = 0;
for ( char *part = strtok( mystring, separator ); part; part = strtok( NULL, separator ) )
{
type[number_of_variables] = atoi(part);
part = strtok( NULL, separator );
address[number_of_variables] = part ? (int)strtol(part, NULL, 16) : 0;
++number_of_variables;
}
for ( size_t i = 0; i < number_of_variables; i++ )
{
printf( "%d\t%x\n", type[i], address[i] );
}
return 0;
}
程序输出为
1 37660
2 38398
您可以编写一个健壮且快速的解析器,保证可以正常工作并且没有这样的错误
文件:lexer.l
%{
#include <stdio.h>
#include "parser.tab.h"
int yyerror(const char *const message);
%}
%option noyywrap
%x IN_ADDRESS
DECIMAL [0-9]+
HEX "0x"[a-fA-F0-9]+
DELIMITER "///"
%%
<*>{DELIMITER} { return DELIMITER; }
<INITIAL>{DECIMAL} {
char *endptr;
// Make the lexer know that we are expecting a
// hex number
BEGIN(IN_ADDRESS);
// Asign the value to use by bison
yylval = strtol(yytext, &endptr, 10);
// Check conversion's success
if (*endptr != '[=10=]')
return ERROR;
return TYPE;
}
<IN_ADDRESS>{HEX} {
char *endptr;
// Restore the initial state
BEGIN(INITIAL);
// Asign the value to use by bison
yylval = strtol(yytext, &endptr, 16);
// Check conversion's success
if (*endptr != '[=10=]')
return ERROR;
return ADDRESS;
}
%%
文件:parser.y
%{
#include <stdio.h>
extern int yylex();
extern FILE *yyin;
int yyerror(const char *const message);
#define YYSTYPE int
%}
%token TYPE
%token DELIMITER
%token ADDRESS
%token ERROR
%%
program:
| program statement
;
command: TYPE DELIMITER ADDRESS {
fprintf(stdout, "type %d, address 0x%08x\n", , );
}
;
statement: command
| statement DELIMITER command;
;
%%
int
yyerror(const char *const message)
{
return fprintf(stdout, "error: %s\n", message);
}
int
main(void)
{
yyin = fopen("program.txt", "r");
if (yyin == NULL)
return -1;
yyparse();
}
文件:program.txt
1///0x37660///2///0x38398
用 gcc、bison 和 flex 编译这个相当简单
bison -d parser.y
flex lexer.l
gcc -Wno-unused-function -Wall -Werror lex.yy.c parser.tab.c -o parserparser
当然,这个程序需要一些调整,根据您的需要进行调整应该很简单。
只需在 bison 和 flex 上找到一个简单的教程,以帮助您完全理解这段代码。
我有一个包含数据类型和变量地址的字符串。这些值由“///”分隔,并且它们是交替的(类型 /// 地址 /// 类型 /// 地址 ...)。这些元组的数量不是固定的,并且会因执行而异。
现在我的问题是如何在循环中处理字符串,因为strtok需要先用原始字符串调用,然后用NULL参数调用,但在循环中它必须调用两次。因此,在第一个循环之后,strtok 被调用了三次,这导致 strtok 执行的计数不均匀,而它应该是偶数。我试图通过在循环外处理第一个元组(因为必须使用原始字符串调用 strtok)并在循环内处理其余元组来解决这个问题。
char mystring[128];
char seperator[] = "///";
char *part;
int type [128];
int address [128];
number_of_variables = 0;
part = strtok(mystring, seperator);
type[number_of_variables] = (int) atoi(part);
part = strtok(NULL, seperator);
address[number_of_variables] = (int)strtol(part, NULL, 16);
while(part != NULL){
part = strtok(NULL, seperator);
type[number_of_variables] = (int) atoi(part);
part = strtok(NULL, seperator);
address[number_of_variables] = (int)strtol(part, NULL, 16);
number_of_variables++;
}
所以现在我的 strtok 执行次数是偶数,但是如果我的字符串包含例如 2 个元组,它将第二次进入循环,因此第五次调用 strtok,这会导致程序崩溃,因为 atoi( ) 得到一个错误的指针。
编辑: mystring 的示例:
"1///0x37660///2///0x38398"
1 和 2 是进一步程序的类型标识符。
我可以建议以下循环,如下面的演示程序所示。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char mystring[128] = "1///0x37660///2///0x38398";
char separator[] = "/ ";
int type [128];
int address [128];
size_t number_of_variables = 0;
for ( char *part = strtok( mystring, separator ); part; part = strtok( NULL, separator ) )
{
type[number_of_variables] = atoi(part);
part = strtok( NULL, separator );
address[number_of_variables] = part ? (int)strtol(part, NULL, 16) : 0;
++number_of_variables;
}
for ( size_t i = 0; i < number_of_variables; i++ )
{
printf( "%d\t%x\n", type[i], address[i] );
}
return 0;
}
程序输出为
1 37660
2 38398
您可以编写一个健壮且快速的解析器,保证可以正常工作并且没有这样的错误
文件:lexer.l
%{
#include <stdio.h>
#include "parser.tab.h"
int yyerror(const char *const message);
%}
%option noyywrap
%x IN_ADDRESS
DECIMAL [0-9]+
HEX "0x"[a-fA-F0-9]+
DELIMITER "///"
%%
<*>{DELIMITER} { return DELIMITER; }
<INITIAL>{DECIMAL} {
char *endptr;
// Make the lexer know that we are expecting a
// hex number
BEGIN(IN_ADDRESS);
// Asign the value to use by bison
yylval = strtol(yytext, &endptr, 10);
// Check conversion's success
if (*endptr != '[=10=]')
return ERROR;
return TYPE;
}
<IN_ADDRESS>{HEX} {
char *endptr;
// Restore the initial state
BEGIN(INITIAL);
// Asign the value to use by bison
yylval = strtol(yytext, &endptr, 16);
// Check conversion's success
if (*endptr != '[=10=]')
return ERROR;
return ADDRESS;
}
%%
文件:parser.y
%{
#include <stdio.h>
extern int yylex();
extern FILE *yyin;
int yyerror(const char *const message);
#define YYSTYPE int
%}
%token TYPE
%token DELIMITER
%token ADDRESS
%token ERROR
%%
program:
| program statement
;
command: TYPE DELIMITER ADDRESS {
fprintf(stdout, "type %d, address 0x%08x\n", , );
}
;
statement: command
| statement DELIMITER command;
;
%%
int
yyerror(const char *const message)
{
return fprintf(stdout, "error: %s\n", message);
}
int
main(void)
{
yyin = fopen("program.txt", "r");
if (yyin == NULL)
return -1;
yyparse();
}
文件:program.txt
1///0x37660///2///0x38398
用 gcc、bison 和 flex 编译这个相当简单
bison -d parser.y
flex lexer.l
gcc -Wno-unused-function -Wall -Werror lex.yy.c parser.tab.c -o parserparser
当然,这个程序需要一些调整,根据您的需要进行调整应该很简单。
只需在 bison 和 flex 上找到一个简单的教程,以帮助您完全理解这段代码。