Определение Длины Символьной Строки в C - если вводы данных пользователем содержание строки

-showlocation

, Чтобы облегчить иметь затмение, работающее дважды и знать, какая рабочая область Вы имеете дело с

Eclipse 3.6, добавляет предпочтительную опцию определить, что показать для Workspace name (shown in window title), который работает намного лучше, чем -showlocation по трем причинам:

  1. Вы не должны перезапускать затмение для него для взятия влияния.
  2. Вы можете, выбрал короткий код.
  3. Это кажется первым перед перспективой и именем приложения.
5
задан Zach Smith 29 November 2009 в 03:35
поделиться

6 ответов

Вы столкнулись с точной проблемой, связанной с scanf () и% s - что произойдет, если вы не знаете, какой объем вводимых данных?

Если вы попытаетесь запустить char mystring [0]; , ваша программа отлично скомпилируется. Но вы всегда будете ошибаться. Вы создаете массив размером 0, поэтому, когда вы пытаетесь поместить что-то в этот массив, вы немедленно выйдете за пределы своей строки (поскольку никакая память не будет выделена), что является segfault.

Итак, пункт 1: вы всегда должны выделять размер для вашей строки. Я могу придумать очень мало обстоятельств (хорошо, ни одного), в которых вы хотели бы сказать char mystring [0] , а не char * mystring .

Затем, когда вы используете scanf , вы никогда не захотите использовать "% s" спецификатор - потому что это не будет выполнять проверку границ размера строки. поэтому даже если у вас есть:

char mystring[512];
scanf("%s", mystring);

, если пользователь вводит более 511 символов (поскольку 512-й - \ 0), вы выйдете за пределы своего массива. Способ исправить это:

scanf("%511s", mystring);

Это все, чтобы сказать, что C не имеет возможности автоматически изменять размер строки, если вводимых данных больше, чем вы ожидаете. Это то, что вам нужно делать вручную.

Один из способов справиться с этим - использовать fgets () .

Вы можете сказать:

while (fgets(mystring, 512, stdin))
{
   /* process input */
}

Затем вы можете использовать sscanf ( ) для синтаксического анализа mystring

Попробуйте использовать приведенный выше код со строкой длиной 5. После того, как 4 символа будут прочитаны, этот код снова зацикливается, чтобы получить оставшуюся часть ввода. "Обработка"

6
ответ дан 13 December 2019 в 19:28
поделиться

Пользователь всегда сможет ввести больше символов, что приведет к переполнению буфера (частый источник уязвимостей безопасности). Однако вы можете указать «ширину поля» для scanf, например:

scanf("%50s", mystring);

В этом случае ваш буфер должен быть 51 символом, чтобы учесть 50-символьное поле плюс нулевой терминатор. Или сделайте свой буфер 50 символов и скажите, что scanf - это ширина 49.

2
ответ дан 13 December 2019 в 19:28
поделиться

Это код cbfalconer ( http://cbfalconer.home.att.net/download/index.htm ) с парой незначительных изменений и скомпилированный в один файл:

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

#define INITSIZE   112  /* power of 2 minus 16, helps malloc */
#define DELTASIZE (INITSIZE + 16)

enum {OK = 0, NOMEM};

int fggets(char* *ln, FILE *f)
{
   int     cursize, ch, ix;
   char   *buffer, *temp;

   *ln = NULL; /* default */
   if (NULL == (buffer = malloc(INITSIZE))) return NOMEM;
   cursize = INITSIZE;

   ix = 0;
   while ((EOF != (ch = getc(f))) && ('\n' != ch)) {
      if (ix >= (cursize - 1)) { /* extend buffer */
         cursize += DELTASIZE;
         if (NULL == (temp = realloc(buffer, (size_t)cursize))) {
            /* ran out of memory, return partial line */
            buffer[ix] = '\0';
            *ln = buffer;
            return NOMEM;
         }
         buffer = temp;
      }
      buffer[ix++] = ch;
   }
   if ((EOF == ch) && (0 == ix)) {
      free(buffer);
      return EOF;
   }

   buffer[ix] = '\0';
   if (NULL == (temp = realloc(buffer, (size_t)ix + 1))) {
      *ln = buffer;  /* without reducing it */
   }
   else *ln = temp;
   return OK;
} /* fggets */
/* End of ggets.c */

int main(int argc, char **argv)
{
   FILE *infile;
   char *line;
   int   cnt;

   //if (argc == 2)
      //if ((infile = fopen(argv[1], "r"))) {
         cnt = 0;
         while (0 == fggets(&line, stdin)) {
            fprintf(stderr, "%4d %4d\n", ++cnt, (int)strlen(line));
            (void)puts(line);
            free(line);
         }
         return 0;
      //}
   //(void)puts("Usage: tggets filetodisplay");
   //return EXIT_FAILURE;
} /* main */
/* END file tggets.c */

Я тестировал его, и он всегда даст вам то, что вы хотите.

1
ответ дан 13 December 2019 в 19:28
поделиться

Существует функция ggets (), которая не является частью стандартной библиотеки C. Это довольно простая функция. Он инициализирует массив символов с помощью malloc (). Затем он считывает символы из стандартного ввода по одному символу за раз. Он отслеживает, сколько символов было прочитано, и расширяет массив символов с помощью realloc (), когда в нем заканчивается место.

Он доступен здесь: http://cbfalconer.home.att.net/download/ index.htm

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

2
ответ дан 13 December 2019 в 19:28
поделиться

Обычная практика в C - использовать что-то вроде строки чтения GNU или, возможно, строки редактирования NetBSD, также известной как libedit. (Тот же API, другая реализация и лицензия на программное обеспечение.)

Для более простой программы или программы для домашнего задания вы можете теоретически указать ширину поля для scanf, но более нормальной практикой является fgets () для массив фиксированной ширины, а затем запустите для него sscanf () . Таким образом, вы контролируете количество читаемых строк.

0
ответ дан 13 December 2019 в 19:28
поделиться

. Например, если пользователь вводит свое имя, вы не всегда безопасно увеличивать размер mystring до 35 символов, потому что у некоторых людей действительно длинные имена. Вы не хотите доходить до случая, когда пользователь не может полностью ввести запрашиваемую информацию. Правильный способ сделать это - иметь временный буфер очень большого размера, который будет охватывать все возможные вводы пользователем. Как только пользователь вводит информацию и она сохраняется в буфере, вы затем переносите символы из буфера в mystring, при этом отрубая все лишнее пространство в конце буфера. Вы сможете сказать, какой размер вам нужен для mystring. точно, и вы можете выделить только это количество места для него и сбросить буфер. Таким образом, вы не будете использовать строку, занимающую больше памяти для остальной части программы ... вы будете использовать только строку с нужным вам объемом памяти.

0
ответ дан 13 December 2019 в 19:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: