сканировать строку с неизвестным количеством элементов в массив int на C

#c #arrays #string #strtok #scanf

#c #массивы #строка #strtok #scanf

Вопрос:

Я работаю в программе на C, и у меня есть строка символов с числами, подобная этой:

 5 13 12 7 3 0
  

Я хочу отсканировать ее и поместить каждое из этих целых чисел в массив int. Как мне это сделать?
Это способ использовать sscanf для этого?

Я попробовал следующий код без успеха:

  fgets(datatemp, N*3, stdin);

 k = 0; garb = 'c';
    while(garb != ''){
      garb = strtok(datatemp, " ");
      array[k] = garb;
      k  ;
    }
  

ПРИМЕЧАНИЕ: я должен использовать его в функции, которая будет делать то же самое для многих данных, в которых строка ‘datatemp’ будет иметь неизвестное количество целых чисел (и только целых чисел).

Спасибо за любую помощь.

Комментарии:

1. Преобразуйте весь ввод в строку , используя getline() , а затем разделите строку символом » «, и у вас будет массив ваших чисел в виде строк. Преобразуйте ваши числа из строки в целое число. Это даст вам желаемый целочисленный массив.

2. array[k] = atoi(garb);

3. Почему вы не читаете напрямую из stdin into array , пока scanf не будет успешно

4. int Ограничено ли количество N или это «неизвестное число», такое как 0,1,2,3,…

5. В конце я просто сделал то, что сказал @P0W. Но я все еще пытаюсь поступить по-другому, поскольку это может быть полезно в других ситуациях.

Ответ №1:

 // Adapted from strtok(3) example.

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

int
main(int argc, char *argv[])
{
  char *str1, *str2, *token, *subtoken;
  char *saveptr1,*saveptr2;
  int j;
  char datatemp[ 120 ];
  char delim = ' ';

  fgets(datatemp, 119, stdin);

  /*
   * strtok has to be called with a pointer to the input
   * the first time then with a pointer to the string
   * subsequently
   */

  for(j=1, str1 = datatemp;; j  , str1 = NULL)
  {
    token = strtok_r(str1, amp;delim, amp;saveptr1);

    if(token==NULL)
      break;

    for (str2 = token; ; str2 = NULL)
    {
      subtoken = strtok_r(str2, amp;delim, amp;saveptr2);
      if (subtoken == NULL)
        break;
      printf(" --> %sn", subtoken);
    }
  }

  exit(0);
  

}

Комментарии:

1. Спасибо за ваш ответ. Учитывая, что код довольно сложный, для OP, несомненно, было бы полезно, если бы вы могли добавить некоторое объяснение с помощью встроенных комментариев или текста помимо кода.

2. Примечание: нет необходимости вычитать 1, использовать fgets(datatemp, 120, stdin); или даже лучше fgets(datatemp, sizeof datatemp, stdin); . fgets() уже учитывает '' .

Ответ №2:

Чтобы использовать fgets()/sscanf() по запросу OP, см. Ниже.

Использование fgets()/strtol() обеспечивает лучшую обработку ошибок, чем sscanf() . Рекомендуем strtol()

Чтобы получить наилучший ответ, OP должен предоставить информацию о том, как данные должны храниться (VLA, malloc, по 1 за раз), проблемы с обработкой ошибок и т. Д.

Трудно сказать, почему операционный код не работал, поскольку дефалькация array[] отсутствует, но, возможно, он был слишком мал для тестовых данных, и некоторые из них не были изменены по мере необходимости для ввода различных данных.

 void foo() {
  char buf[100];
  if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EOForIOError();

  int i = 0;
  int n = 0;
  int number;
  // Count the numbers
  while (sscanf(amp;buf[i], "%d %n", amp;number, amp;i) == 1) {
    n  ;
  }

  int num[n];
  i = 0;
  int j;
  // scan again, this time save the numbers
  while (sscanf(amp;buf[i], "%d %n", amp;num[i], amp;j) == 1) {
    i = j;
  }

  // use the numbers
  bar(num, n);
}
  

Приведенный выше код может использовать, скорее всего, пропустить j и использовать while (sscanf(amp;buf[i], "%d %n", amp;num[i], amp;i) == 1); , но мне нужно перепроверить некоторые проблемы с кодовой точкой.

strtol() лучше, чем sscanf() . Для использования предложите вспомогательную функцию:

 // return non-zero on failure 
static int user_strtoi(char **s, int *result) {
  char *endptr;
  errno = 0;
  long num = strtol(*s, amp;endptr, 10);
  if (endptr == *s) return 1; //  fail as nothing was parsed
  if (errno != 0) return 2; //  fail due to overflow
  if (num < INT_MIN || num > INT_MAX)  return 2; //  fail due to overflow
  *result = (int) num;
  *s = endptr;
  return 0;
}
  

Комментарии:

1. array[] — это массив целых чисел, динамически распределяемых с помощью malloc, чтобы соответствовать максимальному размеру чисел, определенных во входном файле. Кроме того, array[] находится внутри вектора структуры, который также выделяется динамически.

2. @user3442466 Предлагает обновить ваш пост, чтобы код включал это важное уточнение. Также опубликуйте более крупный пример выборки данных. 1) Многострочный? 2) В каждой строке одинаковое количество int ? 3) Учитывая, что вам, похоже, нужен массив «массив целых чисел», должен ли весь «массив целых чисел» быть одинаковой длины? 4) как вы хотите обозначить длину int в «массиве целых чисел»? 5) Как вы хотите обозначить длину массива «массива целых чисел»?

Ответ №3:

Вы можете использовать стандартную функцию strtol , объявленную в заголовке <stdlib.h> . Например

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


int main( void ) 
{
    char s[] = "5 13 12 7 3 0";
    size_t l = strlen( s );

    size_t n = 0;

    char *end_ptr = s;
    char **next_ptr = amp;end_ptr;

    errno = 0;

    while ( end_ptr != s   l )
    {
        strtol( *next_ptr, next_ptr, 10 );
        if ( errno != 0 ) break;
          n;
    }

    int a[n];
    memset( a, 0, n * sizeof( int ) );

    end_ptr = s;
    size_t i = 0;
    while ( end_ptr != s   l )
    {
        int value = ( int )strtol( *next_ptr, next_ptr, 10 );
        if ( errno != 0 ) break;
        a[i  ] = value;
    }

    for ( i = 0; i < n; i   ) printf( "%d ", a[i] );
    puts( "" );

    return 0;
}
  

Вывод

 5 13 12 7 3 0
  

Комментарии:

1. Примечание: перед 2-м while циклом предложите другой errno = 0; . Не уверен в преимуществе проверки errno и не проверки (int) , теряет ли диапазон. Предлагаю просто использовать long вместо int .

2. @chux в C atoi определяется как (int) strtol(…).:)

3. atoi() потеря информации должна sizeof(long) > sizeof(int) быть такой (int) strtol() же. Если код связан с errno (переполнением), разумно также беспокоиться о потере данных из-за (int) приведения. IAC, эти проблемы, вероятно, выходят за рамки основной проблемы OP.

4. Это только я, или ваш ввод не соответствует вашему выводу? 0 является ли still и integer правильным?

5. @David C. Rankin Это хорошее замечание! Условие должно быть изменено на endptr != s strlen( s)

Ответ №4:

Я предлагаю использовать strtol в цикле, это быстрее (прямое преобразование без промежуточного буфера), и вы можете проверить наличие ошибок

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

int main(void)
{
    char s[128], *p, *q;
    int i, n, *v;

    /* get user input */
    fgets(s, sizeof s, stdin);
    /* count integers */
    for (p = s, n = 0; ; p = q, n  ) {
        strtol(p, amp;q, 10);
        if (p == q) break;
    }
    v = malloc(sizeof(int) * n);
    /* populate array */
    for (p = s, i = 0; i < n; i  ) {
        v[i] = strtol(p, amp;p, 10);
    }
    /* print array */
    for (i = 0; i < n; i  ) {
        printf("%dn", v[i]);
    }
    free(v);
    return 0;
}