C strtok:如何在两个不同的缓冲区中存储令牌
我有一个字符串,其中包含变量的数据类型和地址。这些值由“//”分隔,它们是交替的(type///address///type///address…)。这些元组的数量是不固定的,可以根据执行情况而变化 现在我的问题是如何在循环中处理字符串,因为strtok需要先用原始字符串调用,然后用NULL参数调用,但在循环中必须调用两次。因此,在第一个循环之后,strtok被调用三次,这导致strtok执行的计数不均匀,而它应该是偶数。我试图通过处理循环外的第一个元组(因为必须使用原始字符串调用strtok)并处理循环内的其余元组来解决这个问题C strtok:如何在两个不同的缓冲区中存储令牌,c,buffer,strtok,C,Buffer,Strtok,我有一个字符串,其中包含变量的数据类型和地址。这些值由“//”分隔,它们是交替的(type///address///type///address…)。这些元组的数量是不固定的,可以根据执行情况而变化 现在我的问题是如何在循环中处理字符串,因为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;
}
您可以编写一个健壮、快速的解析器,它保证能够正常工作,并且没有像这样的bug 文件:lexer.l 用gcc、bison和flex编译这篇文章相当简单
bison-d解析器.y
灵活词汇量
gcc-Wno未使用的函数-Wall-Werror lex.yy.c parser.tab.c-o parserparser
当然,这个程序需要一些调整,根据您的需要进行调整应该很简单
只要找到一个关于bison和flex的简单教程,就可以帮助您完全理解这段代码。您可以提供一些输入字符串的示例吗?为什么不检查
part=strtok(NULL,分隔符)的结果调用atoi
之前,code>是否为NULL?您知道strtok
将第二个参数视为要查找的单个字符的delimeter列表,而不是可能是字符串的单个delimeter?因此,delimeters为“///”
,string为“1///0x37660/…”将看到一个1,然后是NULL,然后是NULL,然后是“0x37660”。请参阅手册页中的
strtok`。添加到@Lougler的注释中,您可能希望使用strstrstr()
,它与strtok()
不同,是可重入的,可用于常量字符串(不修改其参数),并且可以使用任何字符串作为分隔符。是,Vlad的解决方案将起作用,因为他正确地处理了strtok
。原始字符串包含5个值。所以它不是元组字符串,因为原始字符串必须包含偶数个values@Gora没关系。它与您的解决方案配合使用,即使我不理解它。尤其是那个?接线员和电话:0我不知道unterstand@Gora看起来你指的是条件运算符,或者换句话说,三元运算符。如果strtok返回NULL,则默认情况下数组地址的元素值设置为0。您可以选择任何其他值或发出错误信号,而不是0。@Gora它们在C中称为三元运算符。感谢您提供详细的解决方案。不幸的是,我的代码运行在一个更大项目的MatlabS函数中,因此我无法更改编译器或项目指南。我不喜欢当前的解决方案,我不确定是否有一些情况下它不起作用(尽管我还没有找到),但我无能为力;)@Gora我明白了,要找到适合您的情况的其他解析器生成器并不难。虽然我一点也不懂matlab,但对于手头的问题来说,这可能是过火了。
1 37660
2 38398
%{
#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;
}
%%
%{
#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();
}