Как ввести строку с неизвестным размером - PullRequest
0 голосов
/ 02 ноября 2018

Я немного запутался в строках на C. Я понимаю, что объявление размера буфера важно, так как в противном случае это может вызвать переполнение буфера. Но мне нужно знать, как мне взять строковый ввод, размер которого я не знаю. Например, если я хотел взять строку текста у пользователя в качестве входных данных, и у меня не было возможности узнать, как долго будет длиться его текст, как мне это сделать?

Я пытался динамически распределять память, когда пользователь вводит данные. Вот код -

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

int main()
{
    char *str, ch;
    int size = 10, len = 0;
    str = realloc(NULL, sizeof(char)*size);
    if (!str)return str;
    while (EOF != scanf_s("%c", &ch) && ch != '\n')
    {
        str[len++] = ch;
        if (len == size)
        {
            str = realloc(str, sizeof(char)*(size += 10));
            if (!str)return str;
        }
    }
    str[len] = '\0';
    printf("%s\n", str);
    free(str);
}

Проблема в том, что, когда я компилирую его с использованием VS-2017, я получаю эти ошибки-

source.c (10): предупреждение C4473: 'scanf_s': недостаточно аргументов передано для строки формата

source.c (10): примечание: заполнители и их параметры ожидают 2 аргументы с переменным числом, но 1 были предоставлены

source.c (10): примечание: отсутствующий переменный аргумент 2 требуется строка формата "% c"

source.c (10): примечание: этот аргумент используется в качестве размера буфера

Я думаю, что динамическое выделение памяти во время работы (как в приведенном выше коде) должно работать, но я, вероятно, что-то делаю не так. Есть ли способ сделать эту работу?

РЕДАКТИРОВАТЬ: Word.

Ответы [ 5 ]

0 голосов
/ 02 ноября 2018

Проблема в том, что, когда я компилирую его с использованием VS-2017, я получаю эти ошибки-

source.c(10): warning C4473: 'scanf_s' : not enough arguments passed for format string

source.c(10): note: placeholders and their parameters expect 2 variadic arguments, but 1 were provided

source.c(10): note: the missing variadic argument 2 is required by format string '%c'

source.c(10): note: this argument is used as a buffer size

Предупреждение и примечания довольно явные, не так ли?

Поиск соответствующей документации раскрывается в разделе «Замечания»:

В отличие от scanf и wscanf , scanf_s и wscanf_s требуют указания размера буфера для всех входных параметров типа c , C , s , S или наборы управления строкой, которые заключены в [] . Размер буфера в символах передается как дополнительный параметр сразу после указателя на буфер или переменную.

Итак, вы хотите изменить

  while (EOF != scanf_s("%c", &ch) && ch != '\n')

выглядеть как минимум так:

  while (EOF != scanf_s("%c", &ch, sizeof ch) && ch != '\n')

еще лучше было бы обеспечить полную проверку ошибок следующим образом:

  {
    int result;
    while (1 == (result = scanf_s("%c", &ch, sizeof ch)) 
           && ch != '\n')
    {
      ...
    }

    if (EOF == result && ferror(stdin)) /* As scanf'ing uses stdin, 
                                           test its error status. */
    {
      fprintf(stderr, "scanf_s() failed.\n")
    }
  }
0 голосов
/ 02 ноября 2018
  • scanf_s требует размер буфера в качестве аргумента, и вы не хотите, чтобы
  • Обычно scanf будет считываться с stdin, как только \n будет подан в любом случае.
  • Использование getchar вот лучший подход

Вот версия, использующая getchar:

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

int     main()
{
  char  *str = NULL;
  int   ch;
  int   capacity = 10, size = 0;

  str = realloc(str, sizeof(*str) * (capacity + 1));
  if (!str) return 1;
  while ((ch = getchar()) != EOF && ch != '\n')
    {
      if (size == capacity)
      {
        capacity += 10;
        str = realloc(str, sizeof(*str) * (capacity + 1));
        if (!str) return 1;
      }
      str[size] = (char)ch;
      size++;
    }
  str[size] = '\0';
  printf("%s\n", str);
  free(str);
  return 0;
}
0 голосов
/ 02 ноября 2018

scanf_s требует дополнительного параметра «размер буфера» для каждого отформатированного входного заполнителя. Вот на что жалуется ваш компилятор. Поэтому при использовании scanf_s вам придется написать scanf_s("%c", &ch, 1). Но вы также можете просто использовать scanf, так как вы можете гарантировать, что ваш буфер ch достаточно велик, чтобы в любом случае принять символьное значение. Так что scanf("%c",&ch) будет работать надежно.

Обратите внимание, что scanfscanf_s) возвращают количество значений, правильно считанных; Возвращаемое значение 0 также возможно, что также означает, что ничего не было прочитано.

Так что я бы проверил это как ...

while (scanf("%c", &ch)==1 && ch != '\n') 
0 голосов
/ 02 ноября 2018

Ваш код почти в порядке.

Две вещи должны быть изменены:

  1. не используйте scanf, но используйте getc
  2. ch должно быть int, иначе сравнение с EOF вызовет проблемы.
  3. Плохая деталь: main должен вернуть 0 в случае успеха и значение, отличное от 0 в случае ошибки.

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

int main()
{
  char *str;
  int ch;
  int size = 10, len = 0;

  str = realloc(NULL, sizeof(char)*size);
  if (str == NULL)
    return 1;

  while ( (ch = getc(stdin)) && ch != EOF && ch != '\n')
  {
    str[len++] = (char)ch;

    if (len == size)
    {
      str = realloc(str, sizeof(char)*(size += 10));

      if (str == NULL)
        return 1;
    }
  }

  str[len] = '\0';
  printf("%s\n", str);
  free(str);
}
0 голосов
/ 02 ноября 2018
  1. Вы должны использовать getchar, а не scanf_s
  2. Вы должны использовать int ch;, а не char ch; для EOF

Может работать следующее code:

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

int main() {
    char *str = NULL;
    int ch;
    size_t size = 0, len = 0;

    while ((ch=getchar()) != EOF && ch != '\n') {
        if (len + 1 >= size)
        {
            size = size * 2 + 1;
            str = realloc(str, sizeof(char)*size);
        }
        str[len++] = ch;
    }
    if (str != NULL) {
        str[len] = '\0';
        printf("%s\n", str);
        free(str);
    }

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...