Как прочитать набор данных через запятую, используя scanf_s - C Программирование - PullRequest
0 голосов
/ 20 февраля 2020

У меня нет рабочего кода, которым я мог бы поделиться прямо сейчас, но в основном я пытаюсь добиться чтения пользовательского ввода или файла в следующем формате:

1,2
2,5
3,4
4,5
etc...

или

1,3 4,5 6,7 8,6 ... Итак, пара вещественных чисел, разделенных запятыми, и мне нужно будет присвоить их массиву или массиву 2d и вычислить их среднее значение, медиану, режим et c ...

Я пробовал scanf_s("%d,",&n) и все в таком духе, но пока ни один из них не удался. Я действительно новичок в C и пришел с Java, поэтому все было очень запутанно. Если какие-либо советы или просто пример будет принята с благодарностью. Я знаю, что вы также можете использовать fgets, gets или sscanf, однако я еще не изучил их.

Это был код, отправленный другим пользователем: (но я не совсем понимаю его, потому что он дал мне sr c может быть 0 ошибка)

#include <stdio.h>
#include <stdlib.h>
int main( void )
{
  char *src = (char*)malloc(sizeof(char) * 500);
  fgets(src, 500, stdin);
  int arr[500];
  int index = 0;
  int n;

  while ( sscanf ( src, "%d,%n", &arr[index], &n ) == 1 ) {  
    printf("%d\n", arr[index]);
    index++;
    src += n;
  }
  return 0;
}

Ответы [ 3 ]

1 голос
/ 20 февраля 2020

Используйте

scanf_s("%d,%d", &n1, &n2);

, чтобы прочитать оба числа в каждой строке одновременно. Вы не можете использовать %d, для второго числа, потому что после него нет запятой.

scanf() возвращает количество обработанных входных данных. Поскольку вы читаете два числа одновременно, вы должны проверить, что он возвращает 2, а не 1.

int n1, n2;
while (scanf("%d , %d", &n1, &n2) == 2 ) { 
    printf("first number = %d, second number = %d\n", n1, n2);
}
0 голосов
/ 20 февраля 2020

Есть (как минимум) два основных решения. Один из них заключается в том, чтобы продолжать читать числа в одиночку, поэтому вас действительно не слишком беспокоит наличие запятых или нет; другой - читать числа в парах.

Опция A включает в себя небольшую настройку строки формата от "%d,%n" до "%d %n", чтобы вы узнали, где заканчивается число (точнее, где первый символ это не пробел появляется после числа), и пропустите запятую отдельно в al oop:

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

int main(void)
{
    char data[500];
    char *src = data;
    fgets(src, 500, stdin);
    int arr[500];
    int index = 0;
    int n;

    while (sscanf(src, "%d %n", &arr[index], &n) == 1)
    {
        printf("%d\n", arr[index++]);
        src += n;
        if (*src == ',')
        {
            putchar('=');
            src++;
        }
    }
    return 0;
}

putchar('=') позволяет мне видеть, когда запятая пропущена; он не будет присутствовать в «производственном» коде.

Пример вывода (Bash Здесь String запись):

$ read41 <<< '1,2  3,4   5,6   7, 8   9,10, 11 , 12xyz'
1
=2
3
=4
5
=6
7
=8
9
=10
=11
=12
$

Будьте осторожны - завершающий пробел в формате scanf() разрушительно для интерактивного ввода, но безвредно для sscanf(). Обратите внимание, что в данных есть случайная запятая после 10, но эта версия кода не заботится об этом. Ему также не важно, где символы новой строки появляются парами (или не будет, если он повторяется на while (fgets(data, sizeof(data), stdin) != 0) { char *src = data; … }).

Опция B предполагает чтение чисел в парах. Поскольку вы используете sscanf() в al oop, вам все еще нужна спецификация преобразования %n. Второй пробел в строке формата (после запятой) не является строго обязательным (%d пропустит также пробел), но он безвреден и симметричен c. Это требует наличия одной запятой между парами чисел, которые должны находиться на одной строке (но допускается использование пробелов или без пробелов вокруг запятой), и пары должны появляться на одной строке.

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

int main(void)
{
    char data[500];
    int arr[500];
    int index = 0;

    while (fgets(data, sizeof(data), stdin) != 0)
    {
        int n;
        char *src = data;
        while (sscanf(src, "%d , %d %n", &arr[index + 0], &arr[index + 1], &n) == 2)
        {
            printf("(%d,%d)\n", arr[index + 0], arr[index + 1]);
            src += n;
            index += 2;
        }
    }
    return 0;
}

Пример вывода (используя Bash ANSI- C Цитируя тоже):

$ read43 <<< $'1,2  3,4   5,6   7,8\n9,10 11 , 12xyz'
(1,2)
(3,4)
(5,6)
(7,8)
(9,10)
(11,12)
$
0 голосов
/ 20 февраля 2020

Если формат ввода может действительно варьироваться (ваш вопрос не совсем уверен в этом), strtod() является вашим основным оружием.

char *P = MyLine, *NewP;   //MyLine is the input line
double Val[2];
do {
  Val[0]=strtod(P, &NewP);  //It reads the first value and shifts the pointer.
  if (NewP==P) return ERROR_EMPTY_STRING; //No values found! Sometimes maybe OK, if empty lines are allowed.
  P=NewP;
  while (*P == ' ') P++; //Omitting empty space between first value and comma.
  if (*P!=',') return ERROR_WRONG_FORMAT; //Wrong input: no comma between the values!
  Val[1]=strtod(P, &NewP);  //It reads the second value and shifts the pointer.
  if (NewP==P) return ERROR_WRONG_FORMAT; //No second value found! This is definitely not OK.
  P=NewP;
  while (*P == ' ') P++; //Omitting probable trailing spaces (we don't need it for strtod() because it does it by itself, but we need it for the endline check);
  ProcessSomehow(Val);   //Process the pair
} while (*P && *P != '\r' && *P != '\n' );
return LINE_ENDED_OK;

Этот код будет анализировать

1,2
3,4
5,6

, а также

1,2 3,4 5,6
7,8 9,10 11,12

или даже этого

 2, 4 1 , 5 6 ,8
1,3 4, 4
1,4 6 ,4    6, 8   2,7  2, 12  4, 8

всего, если они являются парами, разделенными запятыми, и каждая пара разделена хотя бы одним пространство. Вы также можете легко изменить его, разрешив 1,2; 4, 3; 2, 3 7, 2 или любые другие дополнительные разделители.

#define коды ошибок по своему вкусу (или используйте любую другую обработку ошибок, если хотите).

...