我有一个程序应该打印一个简单的直方图。
下面的代码不是一个最小的可重现示例,因为完整代码超过 100 行,这只是理解所必需的部分。如果有人需要完整的代码来回答我的问题,我会更新它。
#define LINE_CHAR '#'
void printHistogram(FILE * const file, size_t const fields_size, char const * const * const names, unsigned const * const data) {
// for all the names we are using the same buffer to avoid unnecessary heap allocations
size_t const name_buffer_size = max_string_length(fields_size, names) + 1;
char name_buffer[name_buffer_size];
name_buffer[name_buffer_size - 1] = '\0';
// same for the lines representing data
size_t line_buffer_size = max_unsigned(fields_size, data) + 1;
char line_buffer[line_buffer_size];
memset(line_buffer, LINE_CHAR, line_buffer_size);
for (size_t i = 0; i < fields_size; i++) {
size_t current_name_length = strlen(names[i]);
// fill the rest of the space with spaces
memset(name_buffer + current_name_length, ' ', name_buffer_size - 1 - current_name_length);
// copy name to buffer without null terminator
memcpy(name_buffer, names[i], current_name_length);
// prevent printing out the whole buffer, instead only print the required part
line_buffer[data[i] + 1] = '\0';
fprintf(file, "%s|%s\n", name_buffer, line_buffer);
// remove this early terminator
line_buffer[data[i] + 1] = LINE_CHAR;
}
}
int main() {
char const * const names[] = {"a", "b", "abc"};
unsigned const data[] = {5, 10, 15};
printHistogram(stdout, 3, names, data);
}
预期:
a |######
b |###########
abc|################
得到:
a |######
b |###########
|################
在最后一次迭代中,代码只是跳过名称缓冲区,这是为什么?
这些行:
line_buffer[data[i] + 1] = '\0';
...
line_buffer[data[i] + 1] = LINE_CHAR;
如果 line_buffer
是最大值,则写入超出
data[i]
数组的限制。另请注意,输出显示 #
太多(我认为这也是预期输出中的拼写错误)。
应删除
+1
:
line_buffer[data[i]] = '\0';
...
line_buffer[data[i]] = LINE_CHAR;
但是,应该提到的是,通过在
fprintf()
: 中使用格式说明符可以显着简化代码
for (size_t i = 0; i < fields_size; i++) {
fprintf(file, "%-*s|%.*s\n", max_name_size, names[i], data[i], line_buffer);
}