В C: Как определить окончание строки - PullRequest
1 голос
/ 11 октября 2019

Я делаю программу для отображения ненулевого элемента в n * n матрице

ex. первый. Я введу строку & col

, затем введите матрицу, которую я хочу проанализировать.

проблема здесь!

например, если я хочу получить 4 *4 матрицы

мой тип ввода будет выглядеть так:

input:    
    0 0 4 0
    0 4 0 5
    1 7 5 8
    1 0 5 4

, и я хочу вывести «ошибку», когда кто-то вводит 4 * 4, как это (это 2 * 12)

input:
    1 0 4 2 0 4 1 4
    5 0 1 4 8 0 0 4

или что (даже не квадрат)

input:
   1 2 4 2 5 4 1 7 8 1
   4 5 7 0 0 5


  #include <stdio.h>
  void main(){

  int i;
  int j;
  int row;
  int col;

  printf("Please Enter Row & Column : ");
  scanf("%d%d",&row,&col);

  int a[row][col];

  printf("Please Enter Matrix: \n");
  for (i=0; i<row; i++){
       for(int j=0; j<col;j++){

       scanf("%d",&a[i][j]);
       }
  }

  int size =0;
      for (i=0;i<row;i++)
          for (j = 0; j <col; j++)
              if(a[i][j] != 0)
                  size++;

  int b[size][3];


      int k = 0;
      for (int i = 0; i < row; i++)
          for (int j = 0; j <col; j++)
              if (a[i][j] != 0)
              {
                  b[k][0] = i;
                  b[k][1] = j;
                  b[k][2] = a[i][j];
                  k++;
              }
  for (int i=0; i<size; i++)
      {
          for (int j=0; j<3; j++)
              printf("%d ", b[i][j]);

          printf("\n");
      }
      return 0;

  }

Ответы [ 2 ]

4 голосов
/ 11 октября 2019

Создайте буфер и прочитайте всю строку с fgets. Затем используйте strtok и strtol для анализа целых чисел.

fgets: https://en.cppreference.com/w/c/io/fgets

strtok: https://en.cppreference.com/w/c/string/byte/strtok

strtol:https://en.cppreference.com/w/c/string/byte/strtol

А вот пример кода:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLEN 65535
#define M_SIZE 4

int main() {
    char buf[MAXLEN];
    int matrix[M_SIZE][M_SIZE];

    for (int i = 0; i < M_SIZE; i++) {
        // read the whole line
        fgets(buf, MAXLEN, stdin);

        char* num_str = strtok(buf, " ");  // get first integer
        for (int j = 0; j < M_SIZE; j++) {
            if (num_str == NULL) {
                printf("less than 4 integers inputted in one line\n");
                return -1;
            }
            matrix[i][j] = strtol(num_str, NULL, 10);
            num_str = strtok(NULL, " ");  // get next integer
        }

        if (num_str != NULL) {  // if the next integer exists
            printf("more than 4 integes inputted in one line");  // this is the error you want
            return -1;
        }
    }

    return 0;
}

Другой способ заключается в использовании sscanf в соответствии с комментарием

sscanf Поведениетак же, как scanf, за исключением того, что в качестве входных данных используется строка. Возвращает аргумент, который он проанализировал. Помещение «% n» в строку формата поместит количество прочитанных до сих пор символов в назначенный тип int и не увеличит число, возвращаемое функцией. https://en.cppreference.com/w/c/io/fscanf

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLEN 65535
#define M_SIZE 4

int main() {
    char buf[MAXLEN];
    int matrix[M_SIZE][M_SIZE];

    for (int i = 0; i < M_SIZE; i++) {
        // read the whole line
        fgets(buf, MAXLEN, stdin);

        int parsed_len;
        int ret = sscanf(buf, "%d %d %d %d %n", &matrix[i][0], &matrix[i][1], &matrix[i][2], &matrix[i][3], &parsed_len);  // parse the line
        if (ret < 4) {
            printf("less than 4 integers inputted in one line\n");
            return -1;
        }
        else if (parsed_len == strlen(buf)) {
            printf("more than 4 integes inputted in one line\n");  // the error you want
            return -1;
        }
    }

    return 0;
}
0 голосов
/ 13 октября 2019

Вы могли бы сделать что-то вроде:

/* 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 ... но я действительно не думаю, что это стоит.

Обратите внимание, что в обоихВ этих примерах я указал размер матрицы в качестве аргументов командной строки. Это кажется подходящим, поскольку ваш код, похоже, предназначен для интерактивного использования. Если вы хотите прочитать параметры из потока данных, это довольно тривиальное изменение. Просто прочитайте из потока вместо анализа командной строки.

...