我有一个包含数据类型和变量地址的字符串。这些值由" ///"分隔。它们是交替的(类型///地址///类型///地址...)。这些元组的数量不固定,并且可以在执行之间变化。
现在我的问题是如何在循环中处理字符串,因为需要首先使用原始字符串调用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是进一步程序的类型标识符。
答案 0 :(得分: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
答案 1 :(得分:2)
你可以编写一个健壮且快速的解析器,保证工作并且没有像这样的错误
文件: 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 != '\0')
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 != '\0')
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", $1, $3);
}
;
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 的简单教程,以帮助您完全理解此代码。