问题是 OP 分配了足够的内存来存储max * max 字符(其中max 是输入的最大值),而他们需要的是max * count(其中count 是输入的值的数量)如果只允许正数。
此外,由于缺少正确的free 调用,程序会泄漏内存。
处理内存管理的一种更简单的方法(如果 OP 可以使用符合 C99 的编译器进行编译)是使用可变长度数组:
char matrix[rows][cols]; // where rows and cols aren't known at compile time
如果 VLA 不是一个选项,内存仍然可以连续分配:
#include <stdlib.h>
char **matrix = malloc(rows * sizeof(*matrix));
if ( !matrix )
exit(EXIT_FAILURE);
matrix[0] = malloc(rows * cols * sizeof(**matrix));
if ( !matrix[0] ) {
free(matrix);
exit(EXIT_FAILURE);
}
for ( int i = 1; i < rows; ++i )
matrix[i] = matrix[i - 1] + cols;
// do something with 'matrix'...
free(matrix[0]);
free(matrix);
另一个潜在问题是负责输入的循环不会将输入的值的数量限制为缓冲区的大小 (80),也不会检查这些值是否真的是数字。
以下是一个完整的工作实现(带有一些辅助函数):
#include "stdio.h"
#include "limits.h"
#define MAX_ARR_SIZE 80
int min (int a, int b) {
return a < b ? a : b;
}
int max (int a, int b) {
return a > b ? a : b;
}
void draw_bar_chart (FILE *out_stream, char fill_char,
int *arr, int size,
int bottom, int top);
int read_ints (FILE *in_stream,
int *arr, int size,
int *min, int *max);
int main(void) {
int min_value, max_value;
int values[MAX_ARR_SIZE];
int n_values = read_ints(stdin, values, MAX_ARR_SIZE,
&min_value, &max_value);
// Avoid clipping the chart
int top_view = max(max_value, 0);
int bottom_view = min(min_value, 0);
draw_bar_chart(stdout, '#', values, n_values, bottom_view, top_view);
}
int read_ints (FILE *in_stream,
int *arr, int size,
int *min, int *max) {
int count = 0;
*min = INT_MAX;
*max = INT_MIN;
// Reads up to 'size' values to avoid buffer overflow.
while ( count < size && fscanf(in_stream, "%d", &arr[count]) == 1 )
{ // note that it stops when the read fails (EOF or not an int) ^^^^
if ( arr[count] > *max )
*max = arr[count];
if ( arr[count] < *min )
*min = arr[count];
++count;
}
return count;
}
void tidy_up (int a, int b, int *min, int *max) {
if ( a > b ) {
*min = b;
*max = a;
} else {
*min = a;
*max = b;
}
}
void draw_bar_chart (FILE *out_stream, char fill_char,
int *arr, int size,
int bottom, int top) {
int draw_height = top - bottom;
int i, j, start, end;
// VLA, requires a C99 compliant compiler
char canvas[draw_height][size + 1];
// null-terminates every row to make output easier
for ( i = 0; i < draw_height; ++i )
canvas[i][size] = '\0';
// The "drawing" can be done in many ways...
for ( j = 0; j < size; ++j ) {
tidy_up(top, top - arr[j], &start, &end);
for ( i = 0; i < start; ++i )
canvas[i][j] = ' ';
for ( ; i < end; ++i )
canvas[i][j] = fill_char;
for ( ; i < draw_height; ++i )
canvas[i][j] = ' ';
}
for ( i = 0; i < draw_height; ++i ) {
fprintf(out_stream, "%s\n", canvas[i]);
}
}
例如,给定那些输入
1 5 6 9 8 7 3 2 0 -3 -8 -5 -4 1 1 2 0 1 q
输出:
#
##
###
####
#####
#####
######
####### #
######## ### #
####
####
####
###
##
#
#
#
值得注意的是,对于这个特定的任务,我们根本不需要使用临时二维数组。负责打印图表的函数可以这样实现:
void draw_bar_chart (FILE *out_stream, char fill_char,
int *arr, int size,
int bottom, int top) {
int start, end;
// "draws" the chart by determining if the current position is inside a bar
for ( int i = top - 1; i >= bottom; --i ) {
for ( int j = 0; j < size; ++j ) {
tidy_up(0, arr[j], &start, &end);
putc((i >= start && i < end ? fill_char : ' '), out_stream);
}
puts("");
}
}