Вы могли бы сделать что-то вроде:
/* Read text data into an array. */
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
struct args {
int rows; /* number of rows in the matrix */
int cols; /* number of columns in the matrix */
};
void die(const char *fmt, ... ) __attribute__ ((format (printf, 1, 2)));
void usage(const char *name);
void parse_args(int argc, char **argv, struct args *A);
int
main(int argc, char **argv)
{
struct args A;
int row=0, col=0; /* indices into the array */
parse_args(argc, argv, &A);
int a[A.rows][A.cols];
char buf[1024];
char *end;
while( fgets(buf, sizeof buf, stdin) ) {
if( row >= A.rows ) {
die("Too many lines of input");
}
for( end=buf, col=0; col < A.cols && end < buf + sizeof buf; col++ ) {
char *s = end;
a[row][col] = strtol(end, &end, 10);
if(! isspace(*end) || (end == s)) {
die("invalid input at line %d, column %ld: '%c'",
row + 1, end - buf + 1, *end);
}
}
if(col != A.cols) {
die("missing inputs in line %d.", row + 1);
}
while(isspace(*end)) {
end += 1;
}
if( *end ) {
die("extra data in line %d", row + 1);
}
row += 1;
}
for( row=0; row < A.rows; row++ ) {
printf("%d: ", row);
for(col=0; col < A.cols; col++) {
printf("%d ", a[row][col]);
}
printf("\n");
}
}
void die(const char *fmt, ... )
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}
void
usage(const char *name)
{
const char *base = strrchr(name, '/');
printf("usage: %s rows columns", base ? base + 1 : name);
puts("\n\nrows and columns must be positive integers");
exit(EXIT_SUCCESS);
}
void
parse_args(int argc, char **argv, struct args *A)
{
char *end;
int ch;
if( argc < 3 ) {
usage(argv[0]);
}
while( (ch = getopt(argc, argv, ":bf:")) != -1 ) {
switch( ch ) {
case 'h': usage(argv[0]);
default: die("Unexpected option: %s (-h for usage)", argv[optind-1]);
}
}
argc -= optind;
argv += optind;
A->rows = strtol(argv[0], &end, 10);
if( A->rows < 0 || *end ) {
die("invalid parameter: %s (-h for usage)", argv[0]);
}
A->cols = strtol(argv[1], &end, 10);
if( A->cols < 0 || *end ) {
die("invalid parameter: %s (-h for usage)", argv[1]);
}
}
, но я бы сказал, что вы не должны. Этот формат ввода действительно не подходит. Если у вас есть такие неструктурированные данные, вы должны настаивать на том, чтобы производитель использовал лучший формат. Если вы не можете сменить производителя, вам следует использовать другой язык для изменения данных, чтобы сделать их более подходящими. Например, ваш код на C может быть просто:
/* Read integer data into an array. */
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
unsigned rows, cols;
if( argc != 3 ||
( rows = strtol(argv[1], NULL, 10)) == 0 ||
( cols = strtol(argv[2], NULL, 10)) == 0
) {
fputs("invalid parameters\n", stderr);
return EXIT_FAILURE;
}
int a[rows][cols];
if(fread(a, sizeof **a, rows* cols, stdin) != rows * cols) {
fputs("Unexpected EOF\n", stderr);
return EXIT_FAILURE;
}
}
, и для данного файла ввода текста вы можете использовать его с:
perl -ane 'print pack("i*", @F)' input | ./a.out ${N?} ${M?}
Обратите внимание, что теперь это будет работать с вводомфайл, в котором все данные находятся в одной строке, или если данные структурированы неправильно. (например, одну строку с 5 записями и другую строку с 3 записями можно прочитать как матрицу 2x4 или 4x2). Является ли это проблемой или особенностью, зависит от наблюдателя. Если это особенность, ничего не нужно делать. Если это проблема, поместите проверку ошибок в фильтр (например, perl
), а не в код Си. Если вы хотите проверить формат, вы можете передать конечный символ в поток данных в конце каждой строки (например, perl -lane 'print pack("i*", @F)' input
, чтобы поставить новую строку после каждой строки), а затем перечитать по одной строке за раз, затем выполнитьgetchar, чтобы убедиться, что есть '\n'
, а затем в конце сделать getchar и убедиться, что вы получите EOF ... но я действительно не думаю, что это стоит.
Обратите внимание, что в обоихВ этих примерах я указал размер матрицы в качестве аргументов командной строки. Это кажется подходящим, поскольку ваш код, похоже, предназначен для интерактивного использования. Если вы хотите прочитать параметры из потока данных, это довольно тривиальное изменение. Просто прочитайте из потока вместо анализа командной строки.