Простое чтение строки произвольного (любого) размера из консоли в языке си (C , С)

Forums:

Читать будем блоками из стандартного потока ввода, оригинал здесь = http://www.cplusplus.com/forum/beginner/... ,
а русские комментарии к коду, собственно, на этой вот странице.

vedro-compota's picture

собственно, код следующий ,но со смыслом пока туго. =

/* функция ниже считывает строчку переменной длинны и возвращает указатель на область памяти, 
занимаемую считанной строкой.*/
char* simple_readline( const char* prompt, unsigned block_size )
  {
  char* result;   /* The malloc()ed string to return = "ответ" нашей функции вызывающему её блоку */
  char* block;    /* Each chunk of the string  = очердной кусок читаемой строки */
  char* ok;       /* Used to check for input errors  = идентификатор ошибки , которая может возникнуть при чтении.*/
  unsigned size;  /* The current size of the entire string , размерность читаемого блока данных  (читать будем из стандартного потока ввода.) */
  unsigned n;     /* strlen() of the last block = длинна (в символах) последнего прочитанного блока - беззнаковый тип */

  if (!block_size) block_size = 50; /* */

  if (prompt) printf( "%s", prompt );

  block = result = (char*)malloc( size = block_size ); /* выделям память размера block_size  и одновременно размер размер возвращаемой строки
   также получает значение блок - сайз.*/
  if (!result) return NULL; /* если предыдущая операция завершилась неудачей , то завершаем эту функцию (чтения строки) и передаём наверх НАЛЛ*/
  *result = '\0'; /* инициализируем область памяти  */

  for (;;)
    {
    /* Get the next block of characters until EOL  = читаем следующий (если не первый - то следующий) блок символов
	до тех пор пока не встретиться символ конца строки*/
    ok = fgets( block, block_size, stdin );
    if (!ok) break;

    /* If we found EOL we are done  если вдруг последний символ очередного прочитанного
	блока - это конец строки, то выходим из цикла командой break; */
    n = strlen( block ); 
    if (block[ n -1 ] == '\n') break;

    /* Else add more memory and try again = если же мы ещё не достигли конца читаемой из консоли строки
 то выделяем доболнительную память , чтобы разместить новые считанные блоки	*/
    ok = (char*)realloc( result, size += block_size );
    if (!ok) break;

    result = ok;
    }

  if (!(*result))
    {
    free( result );
    result = NULL;
    }

  return result;
  }

_____________
матфак вгу и остальная классика =)

vedro-compota's picture

Описание этой функции и последующих взяты с сайта = http://www.codenet.ru/progr/cpp/sprd/fge... (если в этой теме буду использовать другой источник - обязательно дам ссылку)

fgets() -чтение строки из потока (например - стандартного потока ввода stdin или какого-либо файла)
Описание

Считывает литеры из потока fp в строку по указателю
str. Чтение заканчивается, когда встречается литера
`\n' (новая строка), конец файла, возникает ошибка чте-
ния или число прочитанных литер достигает n-1. Строка
завершается 0. Литера '\n' (новая строка) включается в
строку (перед 0).

Использование

   #include <stdio.h>
      char *fgets(char *str, int n, FILE *fp);    /* ANSI */

Возвращаемое значение

Возвращает строку str в случае успеха. Если не было
прочитано ни одной литеры и произошла ошибка чтения
или встречен EOF, возвращает NULL, а строка str оста-
ется без изменения. Если возникла ошибка при чтении,
возвращает NULL, а в строке возможен мусор.

Пример

 #include <stdio.h>
      main()
      {
        char buffer[225];
        int buflen;
        char *result;
        buflen=255;
        fputs("Введите строку данных\n", stdout);
        result=fgets(buffer, buflen, stdin);
        if (!result)
            printf("\n конец файла (EOF) или ошибка
                                               (ERROR)\n");
        else fputs(buffer, stdout);
      }

Рекомендация

Смотрите также fputs, gets, puts.
----------------------
когда fgets читатет строку, то - получившаяся строка завершается нулевым символом '\0'.

_____________
матфак вгу и остальная классика =)

vedro-compota's picture

realloc - переразместить блок памяти
Описание

realloc изменяет размер ранее выделенного блока памя-
ти, на который указывает ptr. Размер этого блока после
обращения к realloc определяется параметром size. Если
size равен 0, блок освобождается и возвращается NULL.
Если ptr равен NULL, то отводится (по malloc) size
байтов памяти и возвращается указатель на этот массив
памяти. Если для расширения текущего блока места не
хватает, будет размещен новый блок, а текущий блок ос-
вободится. Текущие данные перепишутся в новый блок.

Использование

 #include <stdlib.h>
      void *realloc(void *ptr, unsigned size);     /* ANSI */

Возвращаемое значение

Возвращается указатель на переразмещенный блок памя-
ти. Если нет подходящей памяти для выполнения realloc,
возвращается NULL (но память по ptr не освобождается).

Пример

   #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      main()
      {
        char *ptr;
        ptr = realloc(NULL, 20*sizeof(char));
        strcpy(ptr, "Это первая часть, ");
        ptr = realloc(ptr, 100*sizeof(char));
        strcat(ptr, "Это вторая часть);
        printf("%s\n", ptr);
        realloc(ptr, 0);
      }

Рекомендация

Смотрите также calloc, free, malloc.

_____________
матфак вгу и остальная классика =)

vedro-compota's picture

malloc ()- выделение памяти по заданному адресу
Описание

Размещает блок памяти объемом numbytes байтов. Если
numbytes равен 0, то возвращает NULL.

Использование

  #include <stdlib.h>
      void *malloc(unsigned numbytes);            /* ANSI */

Возвращаемое значение

Возвращает указатель на размещенный блок памяти. Либо
возвращает NULL при недостатке памяти или в случае
numbytes==0.

Пример

   #include <stdlib.h>
      #include <stdio.h>
      #define NUM_INTS 7623
      int *memblock;
      main()
      {
        memblock = malloc(NUM_INTS*sizeof(int));
        if (memblock==NULL)
            printf("Нехватка памяти\n");
        else
            printf("Память отведена\n");
        free(memblock);
      }

Рекомендация

Смотрите также calloc, free, realloc, farmalloc.

_____________
матфак вгу и остальная классика =)

vedro-compota's picture

free - освободить память
Описание

Освобождает память по указателю p. Эта память должна
быть выделена ранее с использованием функций calloc,
malloc или realloc. Если p = NULL, free бездействует.
Если был использован флаг компилятора строгой ANSI со-
вместимости, то free возвращает void (т. е. не возвра-
щает значения).
Предостережение: не освобождайте данные более одного раза,
не работайте с освобожденными данными.

Использование

      #include <stdlib.h>
      int free(void *p);                          /* ANSI */

Возвращаемое значение

Возвращает 0 в случае успеха или -1, если испорчен
механизм управления памятью или p ошибочно. Значе-
ние -1 указывает на наличие серьезной ошибки в прог-
рамме. free игнорирует несуразные указатели.

Пример

#include <stdio.h>
      #include <stdlib.h>
      main()
      {
        char * p:
        if ((p = malloc(1000))==NULL)
             printf("Не могу отвести память\n");
              if (free(p) == -1)
                abort();   /* Что-то ужасно плохо */
      }

Рекомендация

Смотрите также calloc, malloc, realloc.

_____________
матфак вгу и остальная классика =)

vedro-compota's picture

но приведённый выше код оказывается неправильным и не сработает , если размер блока окажется меньше, ем длина читаемой строки, подробнее ,причина в том, что при каждой итерациях, с номером >1 мы будем затирать строку result командой =

ok = fgets( block, block_size, stdin );

так как начала областей памяти, на которые указывают result и block могут совпадать.
Подробнее читайте здесь = http://www.daniweb.com/software-developm...
мы же теперь рассмотрим исправленный пример (источник = http://www.daniweb.com/software-developm...)

_____________
матфак вгу и остальная классика =)

vedro-compota's picture

чтение строки любого (произвольного) размера в си (размер блока определён заранее - но вы всегда можете переписать эту функцию - добавив в список параметров размерность читаемого "куска") =

char *simple_readline(void)
{
    const size_t block_size = 5; /*определяем размер блока единовременно считываемых данных*/
    
    char *result, *block, *temp;  /* переменная-результат, переменная для очередного  считанного блока и вспомогательная переменная*/
    size_t size = block_size; /* присваиваем значение*/
    size_t n = 0; /* ещё одна вспомогательная переменная -  в дальнейшем послужит для
 определения значения последнего элемента строки (будем проверять - символ ли переноса это на новую строку)*/

    result = block = (char*)malloc(size); /* выделям область памяти размером с единовременно читаемый
блок данных и переводим два указателя на эту область - в том числе и указатель на строку-результат*/
    
    if (!result)
        return NULL;
    
    *result = '\0';

    for (;;) {
        if (fgets(block, block_size, stdin) == NULL)
            break;

        n += strlen(block);
        
        if (result[n - 1] == '\n')
            break;

        size += block_size;
        temp = (char*)realloc(result, size);
        
        if (temp == NULL)
            break;

        result = temp;
        block = result + n;
    }

    if (result[0] == '\0') {
        free(result);
        result = NULL;
    }

    return result;
}

_____________
матфак вгу и остальная классика =)

ну-ну) ещё бы поменьше лишнего)

_________ _ _ ______
dthcbz фкн вгу and co