Як я магу прачытаць ўваходныя радок невядомай даўжыні?

Калі я не ведаю, як доўга гэта слова, я не магу пісаць голец м [6]; ,
Даўжыня слова, можа быць, дзесяць ці дваццаць доўга. Як я магу выкарыстоўваць Scanf , каб атрымаць ўвод з клавіятуры?

#include 
int main(void)
{
    char  m[6];
    printf("please input a string with length=5\n");
    scanf("%s",&m);
    printf("this is the string: %s\n", m);
    return 0;
}

Калі ласка, увядзіце радок з ікламі = 5
прывітанне
гэта радок: прывітанне

45
выкарыстоўваць паказальнік камбінацыі Realloc
дададзена аўтар pinkpanther, крыніца
Вы можаце адмовіцца ад і у зсапЕ ( «% s», & м) так т ўжо паказальнік на першы элемент м [] у гэтым выразе.
дададзена аўтар Jens, крыніца

9 адказы

<�Моцны> Enter пры забеспячэнні вобласць дынамічна

Е.Г.

#include 
#include 

char *inputString(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
    char *str;
    int ch;
    size_t len = 0;
    str = realloc(NULL, sizeof(char)*size);//size is start size
    if(!str)return str;
    while(EOF!=(ch=fgetc(fp)) && ch != '\n'){
        str[len++]=ch;
        if(len==size){
            str = realloc(str, sizeof(char)*(size+=16));
            if(!str)return str;
        }
    }
    str[len++]='\0';

    return realloc(str, sizeof(char)*len);
}

int main(void){
    char *m;

    printf("input string : ");
    m = inputString(stdin, 10);
    printf("%s\n", m);

    free(m);
    return 0;
}
70
дададзена
апошні пераразмеркаваць у inputString сапраўды неабходна?
дададзена аўтар artm, крыніца
Не пераразмеркаваць (NULL, SizeOf (Char) * памер); так жа, як Таноса (SizeOf (Char) * памер) ? Што з'яўляецца прычынай таго, што пераразмеркаваць пераважны тут?
дададзена аўтар Sri Harsha Chilakapati, крыніца
@MrLister Я люблю мяне некаторы шырокае wchar_tacters выкарыстоўваючы wwchar_t_t ! Я выкарыстоўваю іх увесь час у маёй батарэі wchar_tger, каб адлюстраваць паведамленне пра памылку, калі батарэя занадта diswchar_tged або мае unwchar_tacteristic крывую wchar_tging. (Пашкоджаныя батарэі небяспечныя для rechar_tge і можа каштаваць surwchar_tge для перапрацоўкі)
дададзена аўтар immibis, крыніца
чаму size_t памер = 10 ?
дададзена аўтар galois, крыніца
@Jens Пффф, што, верагодна, будзе аптымізавана прэч. Няма праблем. Але калі вы павінны былі зрабіць глабальны пошук і замену функцыі паўкокс з wchar_t , гэтае рашэнне будзе па-ранейшаму працаваць, у адрозненне ад іншых рашэнняў, якія павінны былі б больш майстраваць!
дададзена аўтар Mr Lister, крыніца
@immibis Вы забыліся націснуць Alt + W для пошуку толькі цэлых слоў.
дададзена аўтар Mr Lister, крыніца
Памножыўшы SizeOf (Char) ? Цьфу.
дададзена аўтар Jens, крыніца
Калі на ўсіх, вы павінны памножыць на SizeOf (* НТР) . Але ўсё-ткі, гэта нястрымная параноя і код пах.
дададзена аўтар Jens, крыніца
@MrLister Менавіта таму правільны шлях, калі наогул, гэта памножыць SizeOf (* вул) так што вы нават не павінны рэдагаваць множання, калі тып змены.
дададзена аўтар Jens, крыніца
@ Sh1 Асноўныя() неабходная для апрацоўкі, калі inputString памылкі() вяртае NULL. Я пакідаю яго (яе).
дададзена аўтар BLUEPIXY, крыніца
@MrLister вобласць для «\ 0» замацаваны.
дададзена аўтар BLUEPIXY, крыніца
@Jens Я хацеў бы напісаць такім чынам, як гэта вызначаецца як SizeOf (Char) гэта 1 .
дададзена аўтар BLUEPIXY, крыніца
@MrLister не прадугледжваецца памер паказаны для першага з'яўляецца 0, таму што гэта нонсэнс. І хоць мы можам праверыць гэта.
дададзена аўтар BLUEPIXY, крыніца
@MinhTran Так, ён не прызначаны для не ўключаць невыкарыстоўваныя вобласці.
дададзена аўтар BLUEPIXY, крыніца
@MrLister я быў няправільна зразуметы. Выпраўлена. дзякуй
дададзена аўтар BLUEPIXY, крыніца
Гэта была пустая трата часу.
дададзена аўтар BLUEPIXY, крыніца
@germanfr Што вы кажаце, паказваючы на ​​што-небудзь рабіць з <�б> стары ( «стары вы б ўцечка памяці»)?
дададзена аўтар BLUEPIXY, крыніца
@germanfr Не, я казаў пра пераразмеркаваць (NULL, SizeOf (Char) * памер); гэтак жа, як Таноса (SizeOf (Char) * памер) . Я не сказаць тое ж самае Таноса і пераразмеркаваць .
дададзена аўтар BLUEPIXY, крыніца
@germanfr Дзе кавалак памяці, каб выклікаць уцечку памяці?
дададзена аўтар BLUEPIXY, крыніца
гэта залежыць ад характарыстык апрацоўваных дадзеных шляхам аптымізацыі.
дададзена аўтар BLUEPIXY, крыніца
@ Sh1 ўпэўнены. фіксаваны. дзякуй.
дададзена аўтар BLUEPIXY, крыніца
@jaska Чаканае значэнне, якое складае прыкладна ад мэтавае пачатковага значэння, але можа быць любым значэннем.
дададзена аўтар BLUEPIXY, крыніца
Можна пазбегнуць такой кошту, калі апрацоўка ў памеры, які, як чакаецца, так як з-за дарагой як такой ажыццяўляецца ў пераразмеркаваць.
дададзена аўтар BLUEPIXY, крыніца
@SriHarshaChilakapati Проста азначае аб'яднанне фармату. Там няма ніякіх праблем з Таноса (SizeOf (Char) * памер) .
дададзена аўтар BLUEPIXY, крыніца
@germanfr Я не разумею вас.
дададзена аўтар BLUEPIXY, крыніца
@germanfr Ён не мае звязаны з ім. Я кажу пра пераразмеркаваць (NULL, SizeOf (Char) * памер); гэтак жа, як Таноса (SizeOf (Char) * памер)
дададзена аўтар BLUEPIXY, крыніца
ня @BLUEPIXY нічога. Я не заўважыў, NULL, таму я думаў, што ты дзе казаць аб замене кожны пераразмеркаваць з Таноса , а не толькі першы. Мне вельмі шкада.
дададзена аўтар germanfr, крыніца
@BLUEPIXY няма, пераразмеркаваць не можа быць заменены Таноса . Калі вы змянілі яго вам прыйдзецца бясплатна памяць раней.
дададзена аўтар germanfr, крыніца
@BLUEPIXY не, гэта не тое ж самае. Замена першага толькі другі можа прывесці да ўцечак памяці.
дададзена аўтар germanfr, крыніца
@BLUEPIXY Таноса стварае памяць. Калі вы стварылі новую памяць і не вызвалілі старыя вы б уцечку памяці. <�Код> пераразмеркаваць клапоціцца пра тое час Таноса ня робіць.
дададзена аўтар germanfr, крыніца
@BLUEPIXY ок я цябе. Я не заўважыў NULL там :)
дададзена аўтар germanfr, крыніца
@BLUEPIXY кавалак, што памяць? Я кажу пра тое, што вы сказалі. Вы сказалі, што замена пераразмеркаваць (...) з Таноса (...) прыводзіць да таго ж паводзіны, а гэта няправільна. Пры пераразмеркаваць паспяхова, ён вызваляе папярэднюю памяць, у той час як Таноса ня робіць. Такім чынам, яны не з'яўляюцца ўзаемазаменнымі, як вы сказалі.
дададзена аўтар germanfr, крыніца
Добра, зараз гэта (і любы Таноса() заснаванае рашэнне) сутыкаецца з праблемай, што рабіць, калі мы бяжым з памяці. <�Код> Асноўны() неабходны для апрацоўкі памылак, калі функцыя inputString() вяртае NULL .
дададзена аўтар sh1, крыніца
Акрамя таго, тая ж памылка з кодам <>, калі (даўжыня> памер) . І SizeOf (Char) заўсёды 1.
дададзена аўтар sh1, крыніца
Гэта, безумоўна, так, што вул [Len] = '\ 0'; вярнуцца пераразмеркаваць (вул, даўжыня); прывядзе да тэрмінатар адкідаюцца. Я думаю, што вы мелі на ўвазе Str [LEN ++] = '\ 0' .
дададзена аўтар sh1, крыніца
(Памер * = 2), тым лепш.
дададзена аўтар KIM Taegyoon, крыніца
Ці можаце вы растлумачыць, чаму inputString() не проста вяртае Str ? Ці з'яўляецца гэта, каб вызваліць невыкарыстоўваныя байты, калі даўжыня ўваходных радкі з стандартнага ўводу менш, чым памер (пачатковы памер)?
дададзена аўтар Minh Tran, крыніца
@artm Не, гэта проста робіць памер буфера, роўны памеру ўваходных радкі (плюс адзін для нулявога сімвала).
дададзена аўтар GriffinG, крыніца

З кампутарамі сёння, вы можаце сысці з вылучэннем вельмі вялікія радкоў (сотні тысяч знакаў), а ці ледзь робіць ўвагнутасць ў выкарыстанні аператыўнай памяці кампутара. Таму я б не занадта турбавацца.

Тым не менш, у старыя часы, калі памяць была ў пашане, звычайная практыка была чытаць радкі ў кавалках. <�Код> fgets чытае да максімальнага ліку сімвалаў ад уваходу, але пакідае астатнюю частку уваходнага буфера некранутага, так што вы можаце прачытаць астатняе зь яго, як вам падабаецца.

У гэтым прыкладзе, я прачытаў у кавалках 200 сімвалаў, але вы можаце выкарыстоўваць любы памер кавалка вы хочаце, вядома.

#include 
#include 
#include 

char* readinput()
{
#define CHUNK 200
   char* input = NULL;
   char tempbuf[CHUNK];
   size_t inputlen = 0, templen = 0;
   do {
       fgets(tempbuf, CHUNK, stdin);
       templen = strlen(tempbuf);
       inputlen += templen;
       input = realloc(input, inputlen+1);
       strcat(input, tempbuf);
    } while (templen==CHUNK-1 && tempbuf[CHUNK-2]!='\n');
    return input;
}

int main()
{
    char* result = readinput();
    printf("And the result is [%s]\n", result);
    free(result);
    return 0;
}

Заўважым, што гэта спрошчаны прыклад, без праверкі памылак; ў рэальным жыцці вы павінны пераканацца, што ўваход OK шляхам праверкі вяртаецца значэння fgets .

Таксама адзначым, што ў канцы, калі працэдура ReadInput, ніякія байты не дарэмна; радок мае дакладны памер памяці ён павінен мець.

10
дададзена
Неабходна праверыць вяртаецца значэнне fgets() , інакш код можа ўвесці бясконцы цыкл.
дададзена аўтар chux, крыніца
@chux OK, дадаў нататку пра гэта.
дададзена аўтар Mr Lister, крыніца
Мае патрэбу апрацоўку памылак для пераразмеркаваць() вяртанне NULL (і, такім чынам, для ReadInput() вяртанне NULL ).
дададзена аўтар sh1, крыніца

Я бачыў толькі адзін проста спосаб чытання калі заўгодна доўгую радок, але я ніколі не выкарыстоўваў яго. Я думаю, гэта выглядае наступным чынам:

char *m = NULL;
printf("please input a string\n");
scanf("%ms",&m);
if (m == NULL)
    fprintf(stderr, "That string was too long!\n");
else
{
    printf("this is the string %s\n",m);
    /* ... any other use of m */
    free(m);
}

<�Код> т паміж % і s паведамляе зсапЕ() , каб вымераць радок і вылучыць памяць для яго і скапіяваць радок у тым, што і для захоўвання адрас гэтай выдзеленай памяці ў адпаведны аргумент. Пасля таго, як вы скончыце з гэтым вы павінны свабодны() гэта.

Гэта не падтрымліваецца на кожным выкананні зсапЕ() , хоць.

Як ужо адзначалася, самым простым рашэннем з'яўляецца ўсталяваць абмежаванне на даўжыню ўводу. Калі вы ўсё яшчэ хочаце выкарыстоўваць Scanf() , то вы можаце зрабіць гэта наступным чынам:

char m[100];
scanf("%99s",&m);

Звярніце ўвагу, што памер м [] павінен быць па крайняй меры адзін байт больш, чым колькасць паміж % і S .

Калі радок ўводзіцца больш, чым 99, то астатнія сімвалы будуць чакаць, каб быць прачытаны іншым абанентам або астатняй часткі радка фармату перадаецца Scanf() .

Як правіла, зсапЕ() не рэкамендуецца для апрацоўкі карыстацкага ўводу. Гэта лепш за ўсё ўжываць для асноўных структураваных тэкставых файлаў, створаных іншым дадаткам. Нават тады, вы павінны быць дасведчаныя аб тым, што ўваход не можа быць адфарматаваны, як вы чакаеце, што хтосьці мог бы перашкаджалі з ім, каб паспрабаваць зламаць вашу праграму.

6
дададзена
@ TimČas: Гэта частка Posix, 2008, які з'яўляецца стандартам. Быў больш ранні падобны GNU пашырэнне і аналагічнае пашырэнне BSD; стандарт Posix закліканы аб'яднаць розныя рэалізацыі. Цалкам магчыма, што ён будзе знайсці свой шлях у будучы стандарт C.
дададзена аўтар rici, крыніца
Звярніце ўвагу, што "% мс» не з'яўляецца стандартным C --- гэта, верагодна, альбо пашырэнне POSIX або пашырэнне GNU.
дададзена аўтар Tim Čas, крыніца
Я таксама забыўся праверыць памылкі выдзялення першапачаткова.
дададзена аўтар sh1, крыніца

Калі я магу прапанаваць больш бяспечны падыход:

Абвясціць буфер досыць вялікі, каб утрымліваць радок:

<�Код> сімвал user_input [255];

Атрымаць ўваход карыстальніка ў бяспечнай чынам:

<�Код> fgets (user_input, 255, STDIN);

Бяспечны спосаб атрымаць ўваход, першы аргумент з'яўляецца паказальнікам на буфер, у якім будзе захоўвацца ўваход, другі максімальны ўваходны функцыі варта чытаць і трэці паказальнік на стандартны ўвод - гэта значыць, калі ўваходны карыстальнік прыходзіць с.

Бяспеку, у прыватнасці, ідзе ад другога аргументу абмяжоўвае колькі будзе прачытана, які прадухіляе перапаўненне буфера. Акрамя таго, fgets клапоціцца аб нулявы ўскраек апрацоўванай радку.

Больш падрабязная інфармацыя на гэтым функцыю .

EDIT: Калі вам трэба зрабіць любы фарматаванне (напрыклад, пераўтварыць радок у лік), вы можаце выкарыстоўваць atoi калі ў вас ёсць ўваход.

5
дададзена
але OP з просьбай, ён не ведае, колькі ён збіраецца ўваход, што калі ён выпадкова хоча ўвесці з> 255
дададзена аўтар pinkpanther, крыніца
IMO fgets (user_input, SizeOf user_input, STDIN); бяспечней.
дададзена аўтар chux, крыніца

Бяспечней і хутчэй (падваенне магутнасці) версія:

char *readline(char *prompt) {
  size_t size = 80;
  char *str = malloc(sizeof(char) * size);
  int c;
  size_t len = 0;
  printf("%s", prompt);
  while (EOF != (c = getchar()) && c != '\r' && c != '\n') {
    str[len++] = c;
    if(len == size) str = realloc(str, sizeof(char) * (size *= 2));
  }
  str[len++]='\0';
  return realloc(str, sizeof(char) * len);
}
3
дададзена
Бескантрольна множанне памер = 2 можа перапоўніцца.
дададзена аўтар melpomene, крыніца
Вы павінны праверыць усе Таноса і пераразмеркаваць выклікае памылкі.
дададзена аўтар melpomene, крыніца
<�Код> запрашэнне павінен быць Const сімвал * .
дададзена аўтар melpomene, крыніца
Множанне на SizeOf (Char) з'яўляецца залішнім; <�Код> SizeOf (Char) 1 па азначэнні.
дададзена аўтар melpomene, крыніца
Звычайна запрашэнне прадастаўляецца праграмістам. Такім чынам, вы не можаце сказаць, што гэта небяспечна. Гэта можа быць небяспечна, калі праграміст задае некаторы спецификатор фармату ў радку. Але я змяніў яго.
дададзена аўтар KIM Taegyoon, крыніца

Вазьміце паказальнік на знак, каб захоўваць неабходны string.If ў вас ёсць некаторы ўяўленне аб магчымым памеры радкі, то выкарыстоўвайце функцыю

char *fgets (char *str, int size, FILE* file);`

інакш вы можаце вылучыць памяць падчас выканання занадта выкарыстоўваючы Таноса() функцыя, якая дынамічна забяспечвае патрабаваную памяць.

1
дададзена

Я ведаю, што я прыехаў пасля 4-х гадоў, і я занадта позна, але я думаю, што ёсць яшчэ адзін спосаб, што хтосьці можа выкарыстоўваць. Я выкарыстаў GetChar() Функцыя, як гэта: -

#include 
#include 
#include 

//I had putten the main Function Bellow this function.
//d for asking string,f is pointer to the string pointer
void GetStr(char *d,char **f)
{
    printf("%s",d);

    for(int i =0;1;i++)
    {    
        if(i)//I.e if i!=0
            *f = (char*)realloc((*f),i+1);
        else
            *f = (char*)malloc(i+1);
        (*f)[i]=getchar();
        if((*f)[i] == '\n')
        {
            (*f)[i]= '\0';
            break;
        }
    }   
}

int main()
{
    char *s =NULL;
    GetStr("Enter the String:- ",&s);
    printf("Your String:- %s \nAnd It's length:- %lu\n",s,(strlen(s)));
    free(s);
}

вось прыклад выканання гэтай праграмы: -

Enter the String:- I am Using Linux Mint XFCE 18.2 , eclispe CDT and GCC7.2 compiler!!
Your String:- I am Using Linux Mint XFCE 18.2 , eclispe CDT and GCC7.2 compiler!! 
And It's length:- 67
1
дададзена

Read непасрэдна ў вылучанае прастору з fgets() .

Спецыяльны догляд неабходна адрозніваць паспяховае чытанне, канец з файла, памылкі ўводу і з-памяці. Належнае кіраванне памяццю неабходна на EOF.

Гэты метад захоўвае лінію ў «\ п» .

#include 
#include 

#define FGETS_ALLOC_N 128

char* fgets_alloc(FILE *istream) {
  char* buf = NULL;
  size_t size = 0;
  size_t used = 0;
  do {
    size += FGETS_ALLOC_N;
    char *buf_new = realloc(buf, size);
    if (buf_new == NULL) {
     //Out-of-memory
      free(buf);
      return NULL;
    }
    buf = buf_new;
    if (fgets(&buf[used], (int) (size - used), istream) == NULL) {
     //feof or ferror
      if (used == 0 || ferror(istream)) {
        free(buf);
        buf = NULL;
      }
      return buf;
    }
    size_t length = strlen(&buf[used]);
    if (length + 1 != size - used) break;
    used += length;
  } while (buf[used - 1] != '\n');
  return buf;
}

прыклад выкарыстання

int main(void) {
  FILE *istream = stdin;
  char *s;
  while ((s = fgets_alloc(istream)) != NULL) {
    printf("'%s'", s);
    free(s);
    fflush(stdout);
  }
  if (ferror(istream)) {
    puts("Input error");
  } else if (feof(istream)) {
    puts("End of file");
  } else {
    puts("Out of memory");
  }
  return 0;
}
0
дададзена
Я выкарыстоўваю кампілятар C ++. На жаль, я быў крыху зьбянтэжаны. Мая памылка
дададзена аўтар Hani Goc, крыніца
Памылка: няправільнае пераўтварэнне з «несапраўдным *» да «зорачкі *» [-fpermissive] ==> зорачкі * buf_new = пераразмеркаваць (BUF, памер);
дададзена аўтар Hani Goc, крыніца
@Hani Goc Які кампілятар вы карыстаецеся? З кампілятар або кампілятар C ++? Ваш каментар ўзгадняецца з кампілятарам C ++, выкарыстоўваючы -fpermissive , але скарга C кампілятар не дасць гэта паведамленне, і гэта паведамленне пазначана C .
дададзена аўтар chux, крыніца

У мяне таксама ёсць рашэнне са стандартнымі ўваходамі і выхадамі

#include
#include
int main()
{
    char *str,ch;
    int size=10,len=0;
    str=realloc(NULL,sizeof(char)*size);
    if(!str)return str;
    while(EOF!=scanf("%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);
}
0
дададзена