我有以下结构定义,旨在表示时间序列图表:
/* MAX TICKS 24 HOURS * 60 MIN * 60 SEC */
#define MAX_TICKS 86400
/* CHART PARAMETERS */
typedef struct {
/* DRAWING AREA WIDGET */
Widget drawingArea;
/* X-AXIS (TIME) */
int x_tick_spacing_px; /* DISTANCE BETWEEN TIME TICKS IN PIXELS. */
int x_num_ticks; /* TOTAL NUMBER OF TIME TICKS. */
int *x_tick_values; /* ARRAY OF TIME TICK VALUES (E.G., 093000 FOR 09:30:00). */
char **x_tick_labels; /* ARRAY OF TIME TICK LABELS, CORRESPONDING TO X_TICK_VALUES. */
} TSChart;
我正在编写一个解析器来处理定义 xaxis 定义的命令:
/* FUNCTION TO PARSE AND EXECUTE COMMANDS */
void parse_command(TSChart *chartData, char *command) {
int arg_count;
char **args;
char *token;
/* ALLOCATE MEMORY FOR ARGS */
args = malloc(MAX_ARGS * sizeof(char *));
if (args == NULL) {
fprintf(stderr, "Memory allocation failed for args.\n");
return;
}
/* INITIALIZE ARGUMENT COUNT TO ZERO */
arg_count = 0;
/* TOKENIZE THE COMMAND */
token = strtok(command, " ");
while (token != NULL && arg_count < MAX_ARGS) {
args[arg_count++] = token;
token = strtok(NULL, " ");
}
/* COMMAND PARSING */
if (arg_count == 0) return;
if(strcmp(args[0], "xaxis") == 0) { xaxis_command(chartData, arg_count - 1, args + 1); return; }
fprintf(stderr, "ERROR: UNKNOWN COMMAND.\n");
/* FREE THE ARGS ARRAY */
free(args);
}
/* FUNCTION TO HANDLE THE "XAXIS" COMMAND */
void xaxis_command(TSChart *chartData, int arg_count, char **args) {
int i;
int spacing; /* TEMPORARY VARIABLE TO STORE SPACE BETWEEN TICKS IN PIXELS */
int num_values; /* TEMPORARY VARIABLE TO STORE THE NUMBER OF VALUES PASSED */
int num_labels; /* TEMPORARY VARIABLE TO STORE THE NUMBER OF LABELS PASSED */
if (arg_count < 2) {
fprintf(stderr, "ERROR: XAXIS COMMAND EXPECTS AT LEAST 2 ARGUMENTS.\n");
return;
}
/* SPACING */
if (strcmp(args[0], "spacing") == 0) {
if (arg_count != 2) {
fprintf(stderr, "ERROR: XAXIS SPACING EXPECTS 1 ARGUMENT.\n");
return;
}
if (sscanf(args[1], "%d", &spacing) == 1) {
chartData->x_tick_spacing_px = spacing;
} else {
fprintf(stderr, "ERROR: INVALID SPACING VALUE.\n");
}
return;
}
/* VALUES */
if (strcmp(args[0], "values") == 0) {
if (arg_count < 2) {
fprintf(stderr, "ERROR: XAXIS VALUES EXPECTS AT LEAST 1 ARGUMENT.\n");
return;
}
num_values = atoi(args[1]);
if (num_values != arg_count - 2) {
fprintf(stderr, "ERROR: NUMBER OF VALUES DOES NOT MATCH EXPECTED COUNT.\n");
return;
}
if (num_values > MAX_TICKS) {
fprintf(stderr, "ERROR: NUMBER OF VALUES EXCEED MAXIMUM COUNT.\n");
return;
}
chartData->x_num_ticks = num_values;
chartData->x_tick_values = (int *)malloc(num_values * sizeof(unsigned int));
if (chartData->x_tick_values == NULL) {
fprintf(stderr, "ERROR: FAILED TO ALLOCATE MEMORY FOR X TICK VALUES.\n");
return;
}
for (i = 0; i < num_values; i++) {
chartData->x_tick_values[i] = atoi(args[i + 2]);
}
return;
}
/* LABELS */
if (strcmp(args[0], "labels") == 0) {
if (arg_count < 2) {
fprintf(stderr, "ERROR: XAXIS LABELS EXPECTS AT LEAST 1 ARGUMENT.\n");
return;
}
num_labels = atoi(args[1]);
if (num_labels != arg_count - 2) {
fprintf(stderr, "ERROR: NUMBER OF LABELS DOES NOT MATCH EXPECTED COUNT.\n");
return;
}
if (num_labels > MAX_TICKS) {
fprintf(stderr, "ERROR: NUMBER OF LABELS EXCEED MAXIMUM COUNT.\n");
return;
}
chartData->x_num_ticks = num_labels;
chartData->x_tick_labels = (char **)malloc(num_labels * sizeof(char *));
if (chartData->x_tick_labels == NULL) {
fprintf(stderr, "ERROR: FAILED TO ALLOCATE MEMORY FOR X TICK LABELS.\n");
return;
}
for (i = 0; i < num_labels; i++) {
if(strcmp(args[i + 2], "_")==0) {
chartData->x_tick_labels[i] = NULL;
} else {
chartData->x_tick_labels[i] = strdup(args[i + 2]);
}
}
return;
}
/* UNKNOWN SUBCOMMAND */
fprintf(stderr, "ERROR: UNKNOWN XAXIS SUBCOMMAND.\n");
}
设置 x_tick_spacing_px 和 int *x_tick_values 的子命令工作正常。 然而,设置 char **x_tick_labels 会导致“中止陷阱” - 没有提供更多详细信息 -
char **x_tick_labels 的内存分配以及后续各个字符串的分配是否正确完成?
我已根据评论更正了各个字符串的分配:
/* FUNCTION TO PARSE AND EXECUTE COMMANDS */
void parse_command(TSChart *chartData, char *command) {
int i;
int arg_count;
char **args;
char *token;
/* ALLOCATE MEMORY FOR ARGS */
args = (char **)malloc(MAX_ARGS * sizeof(char *));
if (args == NULL) {
fprintf(stderr, "Memory allocation failed for args.\n");
return;
}
/* INITIALIZE ARGUMENT COUNT TO ZERO */
arg_count = 0;
/* TOKENIZE THE COMMAND */
token = strtok(command, " ");
while (token != NULL && arg_count < MAX_ARGS) {
args[arg_count] = strdup(token);
token = strtok(NULL, " ");
fprintf(stderr, "DEBUG cli.c arg_count %d token %s\n", arg_count, token);
arg_count++;
}
/* COMMAND PARSING */
if (arg_count == 0) return;
if(strcmp(args[0], "redraw") == 0) redraw_command(chartData);
else if(strcmp(args[0], "line") == 0) line_command(chartData, arg_count, args);
else if(strcmp(args[0], "xaxis") == 0) xaxis_command(chartData, arg_count, args);
else fprintf(stderr, "ERROR: UNKNOWN COMMAND.\n");
/* FREE THE ARGS ARRAY */
for(i=0; i<arg_count; i++) free(args[i]);
free(args);
}
我还包括处理命令本身的函数:
/* FUNCTION TO HANDLE THE "XTICK" COMMAND */
void xaxis_command(TSChart *chartData, int arg_count, char **args) {
int i;
int spacing; /* TEMPORARY VARIABLE TO STORE SPACE BETWEEN TICKS IN PIXELS */
int num_values; /* TEMPORARY VARIABLE TO STORE THE NUMBER OF VALUES PASSED */
int num_labels; /* TEMPORARY VARIABLE TO STORE THE NUMBER OF LABELS PASSED */
if (arg_count < 3) {
fprintf(stderr, "ERROR: XAXIS COMMAND EXPECTS AT LEAST 2 ARGUMENTS.\n");
return;
}
/* SPACING */
if (strcmp(args[1], "spacing") == 0) {
if (arg_count != 3) {
fprintf(stderr, "ERROR: XAXIS SPACING EXPECTS 1 ARGUMENT.\n");
return;
}
if (sscanf(args[2], "%d", &spacing) == 1) {
chartData->x_tick_spacing_px = spacing;
} else {
fprintf(stderr, "ERROR: INVALID SPACING VALUE.\n");
}
return;
}
/* VALUES */
if (strcmp(args[1], "values") == 0) {
if (arg_count < 3) {
fprintf(stderr, "ERROR: XAXIS VALUES EXPECTS AT LEAST 1 ARGUMENT.\n");
return;
}
num_values = atoi(args[2]);
if (num_values != arg_count - 3) {
fprintf(stderr, "ERROR: NUMBER OF VALUES DOES NOT MATCH EXPECTED COUNT.\n");
return;
}
if (num_values > MAX_TICKS) {
fprintf(stderr, "ERROR: NUMBER OF VALUES EXCEED MAXIMUM COUNT.\n");
return;
}
chartData->x_num_ticks = num_values;
chartData->x_tick_values = (int *)malloc(num_values * sizeof(unsigned int));
if (chartData->x_tick_values == NULL) {
fprintf(stderr, "ERROR: FAILED TO ALLOCATE MEMORY FOR X TICK VALUES.\n");
return;
}
for (i = 0; i < num_values; i++) {
chartData->x_tick_values[i] = atoi(args[i + 3]);
}
return;
}
/* LABELS */
if (strcmp(args[1], "labels") == 0) {
if (arg_count < 3) {
fprintf(stderr, "ERROR: XAXIS LABELS EXPECTS AT LEAST 1 ARGUMENT.\n");
return;
}
num_labels = atoi(args[2]);
if (num_labels != arg_count - 3) {
fprintf(stderr, "ERROR: NUMBER OF LABELS DOES NOT MATCH EXPECTED COUNT.\n");
return;
}
if (num_labels > MAX_TICKS) {
fprintf(stderr, "ERROR: NUMBER OF LABELS EXCEED MAXIMUM COUNT.\n");
return;
}
chartData->x_num_ticks = num_labels;
fprintf(stderr, "num_labels %d\n", num_labels);
chartData->x_tick_labels = (char **)malloc(num_labels * sizeof(char *));
if (chartData->x_tick_labels == NULL) {
fprintf(stderr, "ERROR: FAILED TO ALLOCATE MEMORY FOR X TICK LABELS.\n");
return;
}
for (i = 0; i < num_labels; i++) {
if(strcmp(args[i + 3], "_")==0) {
chartData->x_tick_labels[i] = NULL;
} else {
chartData->x_tick_labels[i] = strdup(args[i + 3]);
}
}
goto DEBUG;
return;
}
/* UNKNOWN SUBCOMMAND */
fprintf(stderr, "ERROR: UNKNOWN XTICK SUBCOMMAND.\n");
DEBUG:
fprintf(stderr, "DEBUG cli.c xaxis_command() | chartData->x_num_ticks %d\n", chartData->x_num_ticks);
fprintf(stderr, "DEBUG cli.c xaxis_command() | chartData->x_tick_labels %p\n", chartData->x_tick_labels);
for(i=0; i<chartData->x_num_ticks; i++) {
if(chartData->x_tick_labels[i] != NULL) fprintf(stderr,"x_tick_labels[%d] = #%s#\n", i, chartData->x_tick_labels[i]);
}
}
但仍然是相同的中止陷阱。该过程已正确完成,并且在出现 Abort trap 消息之前不会执行相关结构的读取。
这个答案指的是问题中的发布的第二块代码。
char **x_tick_labels 的内存分配以及后续各个字符串的分配是否正确完成?
是的,看起来是正确的。您的分配/释放没有明显的错误。
但是您的代码还存在一些其他问题。
#1:
在这一部分
while (token != NULL && arg_count < MAX_ARGS) {
args[arg_count] = strdup(token);
token = strtok(NULL, " ");
fprintf(stderr, "DEBUG cli.c arg_count %d token %s\n", arg_count, token);
arg_count++;
}
fprintf
被称为 after 更新 token
。
#2:
在这一部分
/* UNKNOWN SUBCOMMAND */
fprintf(stderr, "ERROR: UNKNOWN XTICK SUBCOMMAND.\n");
DEBUG:
fprintf(stderr, "DEBUG cli.c xaxis_command() | chartData->x_num_ticks %d\n", chartData->x_num_ticks);
a
return
缺失。如果没有它,您就开始使用未初始化的变量。
#3:
在这一部分
args[arg_count] = strdup(token);
没有检查
strdup
返回 NULL
,因此 args[arg_count]
可能会获得值 NULL
。下面的代码以无法接受 args
的方式使用 NULL
。因此,要么您需要在此处进行 NULL
检查,要么必须更改以下代码以处理 NULL
。