फ़िज़ूल () इनपुट से अनुगामी न्यूलाइन वर्ण निकालना


235

मैं उपयोगकर्ता से कुछ डेटा प्राप्त करने और gcc में किसी अन्य फ़ंक्शन को भेजने का प्रयास कर रहा हूं। कोड कुछ इस तरह है।

printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}

हालाँकि, मुझे लगता है कि यह \nअंत में एक नया चरित्र है। इसलिए अगर मैं इसमें प्रवेश Johnकरता हूं तो भेजना समाप्त हो जाता है John\n। मैं उसे कैसे निकालूं \nऔर एक उचित स्ट्रिंग भेजूं।


21
if (!fgets(Name, sizeof Name, stdin))(बहुत कम से कम दो नकारात्मक का उपयोग नहीं करते; और! =)

4
@Roger Pate "दो नकारों का उपयोग नहीं करते" -> हम्म, अगर हम गहरी खुदाई करते हैं तो "नहीं" और "नकार" दोनों ही नकारात्मक हैं । ;-)। शायद "उपयोग करें if (fgets(Name, sizeof Name, stdin)) {
chux -

3
@chux, मुझे यकीन है कि आपका मतलब हैif (fgets(Name, sizeof Name, stdin) == NULL ) {
R साहू

@ रासु सच : pesky !:
chux -

जवाबों:


154

थोड़ा बदसूरत तरीका:

char *pos;
if ((pos=strchr(Name, '\n')) != NULL)
    *pos = '\0';
else
    /* input too long for buffer, flag error */

थोड़ा अजीब तरीका:

strtok(Name, "\n");

ध्यान दें कि strtokफ़ंक्शन अपेक्षा के अनुरूप काम नहीं करता है यदि उपयोगकर्ता एक रिक्त स्ट्रिंग में प्रवेश करता है (यानी केवल एंटर दबाता है)। यह \nचरित्र को बरकरार रखता है।

वहाँ दूसरों के रूप में अच्छी तरह से कर रहे हैं, निश्चित रूप से।


7
कोई भी सी रनटाइम लाइब्रेरी जो थ्रेड अवेयर है (जो कहना है, जो किसी भी मल्टी-थ्रेडेड प्लेटफ़ॉर्म को लक्षित करता है), strtok()थ्रेड सुरक्षित होगा (यह 'इंटर-कॉल' स्टेट के लिए थ्रेड लोकल स्टोरेज का उपयोग करेगा)। उस ने कहा, गैर-मानक (लेकिन आम पर्याप्त) strtok_r()संस्करण का उपयोग करना आम तौर पर बेहतर है ।
माइकल बूर

2
आपके strtokदृष्टिकोण के समान (और यह खाली जानकारी के साथ काम करता है) के लिए पूरी तरह से थ्रेड-सेफ और रीएंटेंट वेरिएंट के लिए मेरा जवाब देखें । वास्तव में, लागू करने strtokका एक अच्छा तरीका उपयोग करना है strcspnऔर strspn
टिम Timस

2
यदि आप ऐसे माहौल में हैं, जहां अधिक लंबी लाइनों का खतरा है, तो दूसरे मामले को संभालना महत्वपूर्ण है। चुपचाप ट्रंकटिंग इनपुट बहुत नुकसानदायक कीड़े पैदा कर सकता है।
मैल्कम मैक्लीन

2
यदि आपको वन-लाइनर्स पसंद हैं और ग्लिबक का उपयोग कर रहे हैं, तो प्रयास करें *strchrnul(Name, '\n') = '\0';
जुड़वाँ

जब strchr(Name, '\n') == NULL, फिर "इनपुट बफर, फ्लैग एरर के लिए बहुत लंबा इनपुट" से अलग हो जाता है, तो अन्य संभावनाएं मौजूद हैं: अंतिम पाठ में या एक दुर्लभ एम्बेडेड अशक्त चरित्र के stdinसाथ समाप्त नहीं हुआ था '\n'
chux -

439

शायद सबसे सरल समाधान मेरे पसंदीदा अल्पज्ञात कार्यों में से एक का उपयोग करता है strcspn():

buffer[strcspn(buffer, "\n")] = 0;

यदि आप इसे संभालना चाहते हैं '\r'(कहते हैं, यदि धारा द्विआधारी है):

buffer[strcspn(buffer, "\r\n")] = 0; // works for LF, CR, CRLF, LFCR, ...

फ़ंक्शन वर्णों की संख्या को तब तक गिनता है जब तक कि वह ( '\r'या '\n'दूसरे शब्दों में, यह पहला '\r'या '\n') नहीं पाता है । यदि यह कुछ भी हिट नहीं करता है, तो यह '\0'(स्ट्रिंग की लंबाई लौटाता है) पर रुक जाता है ।

ध्यान दें कि यह ठीक काम करता है भले ही कोई नई रेखा न strcspnहो , क्योंकि ए पर रुकता है '\0'। उस स्थिति में, पूरी लाइन बस के '\0'साथ बदल रही है '\0'


30
यह भी दुर्लभ bufferसे शुरू होता है '\0', कुछ ऐसा होता है जो buffer[strlen(buffer) - 1] = '\0';दृष्टिकोण के लिए दुःख का कारण बनता है ।
chux -

5
@chux: हाँ, मुझे लगता है कि अधिक लोगों के बारे में पता था strcspn()। पुस्तकालय में अधिक उपयोगी कार्यों में से एक, आईएमओ। मैंने आज इस तरह से आम सी हैक्स का एक गुच्छा लिखने और प्रकाशित करने का निर्णय लिया है; एक strtok_rकार्यान्वयन का उपयोग कर रहा था strcspnऔर strspnपहले में से एक था: codepad.org/2lBkZk0w ( चेतावनी: मैं गारंटी नहीं दे सकता कि यह बग के बिना है; यह जल्दबाजी में लिखा गया था और शायद कुछ है)। मुझे पता नहीं है कि मैं उन्हें अभी तक कहाँ प्रकाशित करूँगा, लेकिन मैं इसे "बिट ट्विडलिंग हैक्स" की भावना से बनाने का इरादा रखता हूं।
टिम Timस

4
मजबूत ट्रिमfgets() करने के तरीकों में देखा गया । यह strcspn()प्रतीत हो रहा है केवल सही एक लाइनर। strlenतेज है - हालांकि उतना आसान नहीं है।
chux - मोनिका

6
@sidbushes: शीर्षक और सामग्री दोनों में प्रश्न, इनपुट सेfgets() अनुगामी न्यूलाइन के बारे में पूछता है । जो हमेशा पहली नईलाइन भी है।
टिम Timस

9
@sidbushes: मैं समझता हूं कि आप कहां से आ रहे हैं, लेकिन मुझे विशिष्ट शब्दों के लिए Google खोज परिणामों के लिए जिम्मेदार नहीं ठहराया जा सकता है। Google से बात करें, मुझसे नहीं।
टिम Timस

83
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';

8
यदि स्ट्रिंग खाली है, तो क्या यह अपवाद नहीं करेगा? जैसे इंडेक्स आउट ऑफ रेंज।
एडवर्ड ओलिमिसन

1
@EdwardOlamisan, स्ट्रिंग कभी खाली नहीं होगी।
जेम्स मोरिस

5
@ जेम्स मॉरिस असामान्य मामलों में fgets(buf, size, ....)-> strlen(buf) == 0। 1) fgets()पहले charएक के रूप में पढ़ता है '\0'। 2) size == 13) fgets()रिटर्न NULLतब bufकुछ भी हो सकता है। (ओपी का कोड हालांकि NULL के लिए परीक्षण करता है) सुझाव:size_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') name[--ln] = '\0';
chux -

2
यदि स्ट्रिंग खाली है तो क्या होगा? ln-1 होगा size_t, इस तथ्य के लिए सहेजें अहस्ताक्षरित है, इस प्रकार यादृच्छिक मेमोरी में लिखना। मुझे लगता है कि आप का उपयोग करना चाहते हैं ssize_tऔर जाँच ln> 0 है।
abligh

2
@ किंवदंतियों 2k: एक संकलन-समय मूल्य (विशेष रूप से एक शून्य मान के रूप में strlen) के लिए एक खोज एक सादे चार-दर-चार खोज की तुलना में अधिक कुशलता से लागू किया जा सकता है। जिस कारण से मैं इस समाधान को एक strchrया strcspnआधारित से बेहतर मानूंगा।
चींटी

17

नीचे दिए गए '\n'स्ट्रिंग से संभावित को हटाने के लिए नीचे एक तेज़ तरीका है fgets()
यह strlen()2 परीक्षणों के साथ उपयोग करता है ।

char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {

  size_t len = strlen(buffer);
  if (len > 0 && buffer[len-1] == '\n') {
    buffer[--len] = '\0';
  }

अब उपयोग करें bufferऔरlen आवश्यकतानुसार।

इस विधि lenके बाद के कोड के लिए एक मूल्य का पक्ष लाभ है । इससे आसानी से तेज किया जा सकता है strchr(Name, '\n')रेफरी YMMV, लेकिन दोनों तरीके काम करते हैं।


buffer, मूल fgets()से "\n"कुछ परिस्थितियों में शामिल नहीं होगा :
ए) लाइन बहुत लंबी थी, bufferइसलिए केवल charपूर्ववर्ती में '\n'सहेजा गया है buffer। अपठित वर्ण धारा में रहते हैं।
बी) फ़ाइल में अंतिम पंक्ति एक के साथ समाप्त नहीं हुई थी'\n'

यदि इनपुट में '\0'कहीं-कहीं अशक्त अक्षर हैं , तो रिपोर्ट की गई लंबाई strlen()में '\n'स्थान शामिल नहीं होगा ।


कुछ अन्य जवाब 'मुद्दों:

  1. strtok(buffer, "\n");'\n'जब bufferहै हटाने में विफल रहता है "\n"। इस उत्तर से - इस सीमा के चेतावनी के उत्तर के बाद संशोधित किया गया।

  2. निम्नलिखित दुर्लभ अवसरों पर विफल रहता है जब पहला charपाठ होता fgets()है '\0'। यह तब होता है जब इनपुट एक एम्बेडेड के साथ शुरू होता है '\0'। फिर निश्चित रूप से की वैध सीमा के बाहर स्मृति तक पहुँच buffer[len -1]बन जाता buffer[SIZE_MAX]है buffer। कुछ हैकर मूर्खतापूर्ण तरीके से UTF16 पाठ फ़ाइलों को पढ़ने की कोशिश कर सकता है या पाया जा सकता है। जब यह उत्तर लिखा गया था तो यह एक उत्तर की स्थिति थी। बाद में एक गैर-ओपी ने इस उत्तर के चेक जैसे कोड को शामिल करने के लिए इसे संपादित किया ""

    size_t len = strlen(buffer);
    if (buffer[len - 1] == '\n') {  // FAILS when len == 0
      buffer[len -1] = '\0';
    }
  3. sprintf(buffer,"%s",buffer);अपरिभाषित व्यवहार है: Ref । इसके अलावा, यह व्हाट्सएप को किसी भी अग्रणी, अलग या अनुगामी के रूप में नहीं बचाता है। अब हटा दिया गया

  4. [बाद में अच्छे उत्तर के कारण संपादित करें ] दृष्टिकोण buffer[strcspn(buffer, "\n")] = 0;की तुलना में प्रदर्शन के अलावा 1 लाइनर के साथ कोई समस्या नहीं है strlen()। ट्रिमिंग में प्रदर्शन आमतौर पर एक मुद्दा नहीं होता है दिया गया कोड I / O है - CPU समय का एक ब्लैक होल। निम्नलिखित कोड को स्ट्रिंग की लंबाई की आवश्यकता है या अत्यधिक प्रदर्शन के प्रति जागरूक होना चाहिए, इस strlen()दृष्टिकोण का उपयोग करें । एल्स strcspn()एक अच्छा विकल्प है।


उपयोगी उत्तर के लिए धन्यवाद। क्या हम उपयोग कर सकते हैं strlen(buffer)जब बफर आकार का उपयोग करके गतिशील रूप से आवंटित किया जाता है malloc?
rrz0

@ Rrz0 buffer = malloc(allocation_size); length = strlen(buffer);खराब है - द्वारा इंगित की गई मेमोरी में डेटा bufferअज्ञात है। buffer = malloc(allocation_size_4_or_more); strcpy(buffer, "abc"); length = strlen(buffer);ठीक है
chux -

इसके लिए धन्यवाद!! मैं एक सीएस कोर्स कर रहा हूँ और यह एक असाइनमेंट के लिए बहुत मददगार था। मैंने स्रोत कोड में आपके उत्तर को श्रेय दिया।
नथानिएल होयट

8

यदि प्रत्येक पंक्ति में '\ n' है, तो उत्पादन आउटपुट से '\ n' निकालने के लिए प्रत्यक्ष

line[strlen(line) - 1] = '\0';

अन्यथा:

void remove_newline_ch(char *line)
{
    int new_line = strlen(line) -1;
    if (line[new_line] == '\n')
        line[new_line] = '\0';
}

1
ध्यान दें कि इसके बजाय इसका उपयोग करना अधिक सुरक्षित होगा । strnlenstrlen
माइक मर्कटोक

3
प्रश्न से जुड़े पहले उत्तर में एक टिप्पणी "राज्यों में ध्यान दें कि strlen (), strcmp () और strdup () सुरक्षित हैं। 'n' विकल्प आपको अतिरिक्त कार्यक्षमता प्रदान करते हैं।"
.tienne

4
@ सेकर नहीं, यह नहीं होगा। डालने से nजादुई रूप से सुरक्षा नहीं बढ़ती है, इस मामले में यह वास्तव में कोड को और अधिक खतरनाक बना देगा। इसी तरह strncpy, बहुत ही असुरक्षित फ़ंक्शन के साथ। आप जिस पोस्ट से जुड़े हैं, वह बुरी सलाह है।
एमएम

3
यह एक रिक्त स्ट्रिंग ( "") के लिए बुरी तरह विफल रहता है । साथ ही strlen()रिटर्न भी size_tनहीं int
एल्क

4
यह एक खाली स्ट्रिंग के लिए असुरक्षित है, यह इंडेक्स -1 पर लिखेगा। यह प्रयोग न करें।
जीन फ़्राँस्वा Fabre

3

एकल '\ n' ट्रिमिंग के लिए,

void remove_new_line(char* string)
{
    size_t length = strlen(string);
    if((length > 0) && (string[length-1] == '\n'))
    {
        string[length-1] ='\0';
    }
}

कई '\ n' ट्रिमिंग के लिए,

void remove_multi_new_line(char* string)
{
  size_t length = strlen(string);
  while((length>0) && (string[length-1] == '\n'))
  {
      --length;
      string[length] ='\0';
  }
}

1
क्यों घोंसला ifजब आप बस एक शर्त का उपयोग कर लिख सकते हैं &&? उस whileलूप में एक अजीब संरचना है; यह बस हो सकता है while (length > 0 && string[length-1] == '\n') { --length; string[length] = '\0'; }
melpomene

सुझाव के लिए @melpomene धन्यवाद। कोड को अपडेट करें।
BEPP

1
मेरा सुझाव है कि पहला कार्य अधिक स्वाभाविक रूप से परिभाषित किया गया है size_t length = strlen(string); if (length > 0 && string[length-1] == '\n') { string[length-1] = '\0'; }:। यह दूसरी परिभाषा को बेहतर तरीके से दिखाता है (सिर्फ ifइसके बजाय while)।
melpomene

@elpomene धन्यवाद यह समझ में आता है। मैंने कोड अपडेट किया।
बीईपीपी

1

मेरा नौसिखिया तरीका ;-) कृपया मुझे बताएं कि क्या यह सही है। यह मेरे सभी मामलों के लिए काम कर रहा है:

#define IPT_SIZE 5

int findNULL(char* arr)
{
    for (int i = 0; i < strlen(arr); i++)
    {
        if (*(arr+i) == '\n')
        {
            return i;
        }
    }
    return 0;
}

int main()
{
    char *input = malloc(IPT_SIZE + 1 * sizeof(char)), buff;
    int counter = 0;

    //prompt user for the input:
    printf("input string no longer than %i characters: ", IPT_SIZE);
    do
    {
        fgets(input, 1000, stdin);
        *(input + findNULL(input)) = '\0';
        if (strlen(input) > IPT_SIZE)
        {
            printf("error! the given string is too large. try again...\n");
            counter++;
        }
        //if the counter exceeds 3, exit the program (custom function):
        errorMsgExit(counter, 3); 
    }
    while (strlen(input) > IPT_SIZE);

//rest of the program follows

free(input)
return 0;
}

1

शायद सबसे स्पष्ट तरीके से newline वर्ण को हटाने के लिए कदम:

  1. हेडर NAMEका उपयोग करके स्ट्रिंग की लंबाई अंदर निर्धारित करें । ध्यान दें कि समाप्ति को गिनना नहीं है ।strlen()string.hstrlen()\0
size_t sl = strlen(NAME);

  1. देखें कि क्या स्ट्रिंग के साथ शुरू होता है या केवल एक \0वर्ण (खाली स्ट्रिंग) शामिल है। इस मामले में slहो सकता है 0के बाद से strlen()के रूप में मैं नहीं करता है ऊपर कहा गिनती \0और यह की पहली आवृत्ति पर रुक जाता है:
if(sl == 0)
{
   // Skip the newline replacement process.
}

  1. जांचें कि क्या उचित स्ट्रिंग का अंतिम वर्ण एक नया रेखा वर्ण है '\n'। यदि यह मामला है, \nएक के साथ बदलें \0। ध्यान दें कि इंडेक्स काउंट्स शुरू होते हैं 0इसलिए हमें करने की आवश्यकता होगी NAME[sl - 1]:
if(NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

ध्यान दें कि यदि आपने केवल fgets()स्ट्रिंग अनुरोध में दर्ज किया है (स्ट्रिंग सामग्री केवल एक newline वर्ण से मिलकर थी) NAMEस्ट्रिंग इसके बाद एक रिक्त स्ट्रिंग होगी।


  1. हम ifतर्क ऑपरेटर का उपयोग करके चरण 2 और 3. को एक साथ केवल एक-संयोजन में जोड़ सकते हैं &&:
if(sl > 0 && NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

  1. समाप्त कोड:
size_t sl = strlen(NAME);
if(sl > 0 && NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

यदि आप इस तकनीक का उपयोग करने के लिए एक फंक्शन पसंद करते fgetsहैं, तो सामान्य रूप से प्रत्येक और हर बार रीपिट किए बिना आउटपुट स्ट्रिंग्स को संभाल कर , यहाँ है fgets_newline_kill:

void fgets_newline_kill(char a[])
{
    size_t sl = strlen(a);

    if(sl > 0 && a[sl - 1] == '\n')
    {
       a[sl - 1] = '\0';
    }
}

आपके दिए गए उदाहरण में, यह होगा:

printf("Enter your Name: ");

if (fgets(Name, sizeof Name, stdin) == NULL) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}
else {
    fgets_newline_kill(NAME);
}

ध्यान दें कि यदि इनपुट स्ट्रिंग इसमें एम्बेडेड है, तो यह विधि काम नहीं करती \0है। अगर ऐसा होगा strlen()तो केवल पहले तक ही पात्रों की राशि वापस होगी \0। लेकिन यह बहुत सामान्य दृष्टिकोण नहीं है, क्योंकि अधिकांश स्ट्रिंग-रीडिंग फ़ंक्शन आमतौर पर पहले बंद हो जाते हैं\0 और स्ट्रिंग को उस अशक्त चरित्र तक ले जाते हैं।

अपने आप से सवाल के अलावा। अपने कोड को अस्पष्ट बनाने वाले दोहरे नकारों से बचने का प्रयास करें if (!(fgets(Name, sizeof Name, stdin) != NULL) {}:। आप बस कर सकते हैं if (fgets(Name, sizeof Name, stdin) == NULL) {}


निश्चित नहीं कि आप ऐसा क्यों करना चाहेंगे। नई कड़ियों को हटाने की बात यह नहीं है कि तार को समाप्त कर दिया जाए; यह newlines निकालने के लिए है। एक स्ट्रिंग के अंत में एक के \nसाथ प्रतिस्थापित करना नई लाइन को "हटाने" का एक तरीका है। लेकिन एक स्ट्रिंग के भीतर वर्णों को बदलना बुनियादी रूप से स्ट्रिंग को बदल देता है। जानबूझकर कई न्यूलाइन वर्णों के साथ तार होना असामान्य नहीं है, और यह उन तारों के छोर को प्रभावी ढंग से काट देगा। ऐसी नई कड़ियों को हटाने के लिए , सरणी सामग्री को ओवर-राइट लिखने के लिए बाईं ओर शिफ्ट करने की आवश्यकता होती है । \0\n\n
पूर्व निहिलो

@exnihilo उपयोग करके कोई व्यक्ति कई नई लाइनों के साथ स्ट्रिंग का इनपुट कैसे दे सकता है fgets()?
रॉबर्ट्स

ठीक है, आप कई कॉल के द्वारा प्राप्त तार को समाप्‍त कर सकते हैं fgets()। लेकिन मुझे आपकी आपत्ति समझ में नहीं आती है: आप कई नए समाचारों को संभालने के लिए एक प्रस्ताव कोड हैं।
पूर्व निहिलो

@exnihilo You ,re सही है, मैं रणनीति को खत्म कर दूंगा। मैं सिर्फ वांछित परिणाम प्राप्त करने के लिए एक बहुत कठोर लेकिन संभव तरीका जोड़ना चाहता था।
रॉबर्ट्स

@exnihilo ने मेरे उत्तर को पूरी तरह से संपादित किया और उपयोग करके मुख्य दृष्टिकोण का पालन किया strlenआदि। डुप्लिकेट नहीं होने का औचित्य: 1. चरणों द्वारा कोड का स्पष्टीकरण। 2. फ़ंक्शन और संदर्भ-आधारित समाधान के रूप में प्रदान किया गया। 3. दोहरे नकार भाव से बचने के संकेत।
रॉबर्ट्स

0

टिम byस वन लाइनर एक कॉल द्वारा प्राप्त स्ट्रिंग्स के लिए अद्भुत है, क्योंकि आप जानते हैं कि उनके पास अंत में एक ही नई पंक्ति है।

यदि आप एक अलग संदर्भ में हैं और स्ट्रिंग को संभालना चाहते हैं, जिसमें एक से अधिक न्यूलाइन शामिल हो सकते हैं, तो आप स्ट्रैपन की तलाश में हो सकते हैं। यह POSIX नहीं है, जिसका अर्थ है कि आप इसे सभी यूनियनों में नहीं पाएंगे। मैंने अपनी जरूरतों के लिए एक लिखा।

/* Returns the length of the segment leading to the last 
   characters of s in accept. */
size_t strrspn (const char *s, const char *accept)
{
  const char *ch;
  size_t len = strlen(s);

more: 
  if (len > 0) {
    for (ch = accept ; *ch != 0 ; ch++) {
      if (s[len - 1] == *ch) {
        len--;
        goto more;
      }
    }
  }
  return len;
}

सी में एक पर्ल चंप के बराबर की तलाश करने वालों के लिए, मुझे लगता है कि यह ऐसा है (चॉम्प केवल अनुगामी न्यूलाइन को हटाता है)।

line[strrspn(string, "\r\n")] = 0;

Strrcspn फ़ंक्शन:

/* Returns the length of the segment leading to the last 
   character of reject in s. */
size_t strrcspn (const char *s, const char *reject)
{
  const char *ch;
  size_t len = strlen(s);
  size_t origlen = len;

  while (len > 0) {
    for (ch = reject ; *ch != 0 ; ch++) {
      if (s[len - 1] == *ch) {
        return len;
      }
    }
    len--;
  }
  return origlen;
}

1
"क्योंकि आप जानते हैं कि उनमें अंत में एक ही नई पंक्ति होती है।" -> यह तब भी काम करता है जब कोई '\n'(या यदि स्ट्रिंग है "") नहीं है।
chux -

आपकी पहली टिप्पणी के जवाब में, मेरा जवाब है कि संरक्षित करता है। strrcspnजब कोई नहीं है तो मुझे रीसेटलेन फेंकना पड़ा \n
फिलिप ए।

के goto end;बजाय का उपयोग क्यों करें return len;?
चकरली

@chqrlie मुझे इस अतुल्य 2-स्तरीय लूप से बाहर निकलने की आवश्यकता थी जो मुझे मिला। नुकसान हो चुका था। गोटो क्यों नहीं?
फिलिप ए।

आपके पास gotoअपने कोड में दो प्रकार के हैं : एक बेकार gotoजिसे एक returnबयान के साथ प्रतिस्थापित किया जा सकता है और एक बैकवर्ड gotoजिसे बुराई माना जाता है। का उपयोग करने में strchrमदद करता है लागू करने के लिए strrspnऔर strrcspnएक सरल फैशन में: size_t strrspn(const char *s, const char *accept) { size_t len = strlen(s); while (len > 0 && strchr(accept, s[len - 1])) { len--; } return len; }औरsize_t strrcspn(const char *s, const char *reject) { size_t len = strlen(s); while (len > 0 && !strchr(reject, s[len - 1])) { len--; } return len; }
23

0

यदि उपयोग getlineकरना एक विकल्प है - इसकी सुरक्षा के मुद्दों की उपेक्षा नहीं करना और यदि आप पॉइंटर्स को ब्रेस करना चाहते हैं - तो आप getlineवर्णों की संख्या के रिटर्न के रूप में स्ट्रिंग कार्यों से बच सकते हैं । नीचे जैसा कुछ

#include<stdio.h>
#include<stdlib.h>
int main(){
char *fname,*lname;
size_t size=32,nchar; // Max size of strings and number of characters read
fname=malloc(size*sizeof *fname);
lname=malloc(size*sizeof *lname);
if(NULL == fname || NULL == lname){
 printf("Error in memory allocation.");
 exit(1);
}
printf("Enter first name ");
nchar=getline(&fname,&size,stdin);
if(nchar == -1){ // getline return -1 on failure to read a line.
 printf("Line couldn't be read.."); 
 // This if block could be repeated for next getline too
 exit(1);
}
printf("Number of characters read :%zu\n",nchar);
fname[nchar-1]='\0';
printf("Enter last name ");
nchar=getline(&lname,&size,stdin);
printf("Number of characters read :%zu\n",nchar);
lname[nchar-1]='\0';
printf("Name entered %s %s\n",fname,lname);
return 0;
}

नोट : [ सुरक्षा मुद्दों ] के साथ getlineउपेक्षा नहीं की जानी चाहिए।


-1

नीचे फ़ंक्शन स्ट्रिंग प्रोसेसिंग लाइब्रेरी का एक हिस्सा है जिसे मैं गितुब पर बनाए रख रहा हूं। यह एक स्ट्रिंग से अवांछित पात्रों को निकालता है, जो आप चाहते हैं

int zstring_search_chr(const char *token,char s){
    if (!token || s=='\0')
        return 0;

    for (;*token; token++)
        if (*token == s)
            return 1;

    return 0;
}

char *zstring_remove_chr(char *str,const char *bad) {
    char *src = str , *dst = str;
    while(*src)
        if(zstring_search_chr(bad,*src))
            src++;
        else
            *dst++ = *src++;  /* assign first, then incement */

    *dst='\0';
        return str;
}

एक उदाहरण उपयोग हो सकता है

Example Usage
      char s[]="this is a trial string to test the function.";
      char const *d=" .";
      printf("%s\n",zstring_remove_chr(s,d));

  Example Output
      thisisatrialstringtotestthefunction

आप अन्य उपलब्ध कार्यों की जांच करना चाहते हैं, या परियोजना में योगदान भी दे सकते हैं :) https://github.com/fnoyanisi/zString


आप निकाल देना चाहिए *में *src++;और बनाने bad,token औरd const char * । इसके strchrबजाय उपयोग क्यों नहीं zChrSearch? आपके कार्य में *srcनहीं हो सकता । '\0'zStrrmv
चिक्ली

थैंक्स @chqrlie! आपके सुझावों को दर्शाने के लिए कोड को अपडेट किया गया ..... किसी भी मानक पुस्तकालय कार्यों का उपयोग किए बिना एक स्ट्रिंग हेरफेर लाइब्रेरी बनाने के उद्देश्य से zstring एक मजेदार परियोजना के रूप में शुरू हुई, इसलिए मैंने strchr
fnisi

1
" किसी भी मानक पुस्तकालय कार्यों का उपयोग किए बिना " स्ट्रिंग हेरफेर लाइब्रेरी लिखना एक अच्छा व्यायाम है, लेकिन अन्य लोगों को इसका उपयोग करने के लिए क्यों कहें? यदि कुछ भी हो, तो यह किसी भी मानक पुस्तकालय की तुलना में धीमा और कम परीक्षण वाला होगा।
melpomene

यह एक अलग काम कर रहा है जो सवाल के बारे में पूछता है। इसका उपयोग संभवतः एकमात्र नईलाइन से छुटकारा पाने के लिए किया जा सकता है, लेकिन यह ओवरकिल की तरह महसूस करता है।
जोनाथन लेफ्लर

-1
 for(int i = 0; i < strlen(Name); i++ )
{
    if(Name[i] == '\n') Name[i] = '\0';
}

आपको इसके लिए प्रयास करना चाहिए। यह कोड मूल रूप से स्ट्रिंग के माध्यम से लूप करता है जब तक कि यह '\ n' नहीं मिलता। जब यह पाया जाता है कि '\ n' को बदलकर रिक्त वर्ण टर्मिनेटर '\ 0' कर दिया जाएगा

ध्यान दें कि आप वर्णों की तुलना कर रहे हैं और इस पंक्ति में तार नहीं हैं, फिर strcmp () का उपयोग करने की कोई आवश्यकता नहीं है:

if(Name[i] == '\n') Name[i] = '\0';

चूंकि आप एकल उद्धरणों का उपयोग करेंगे और दोहरे उद्धरण चिह्नों का नहीं। यदि आप अधिक जानना चाहते हैं तो यहां सिंगल बनाम डबल कोट्स के बारे में एक लिंक दिया गया है


2
यदि आप अपने कोड के प्रारूप को समझाते और संपादित करते हैं तो बेहतर होगा।
अन्ह फाम १

आमतौर पर अनाम कोड की कुछ पंक्तियों को पोस्ट करने के बजाय किसी समाधान की व्याख्या करना बेहतर होता है। आप पढ़ सकते हैं कि मैं कैसे एक अच्छा उत्तर लिखूं , और पूरी तरह से कोड-आधारित उत्तरों की व्याख्या करना
मासिमिलियानो क्रूस

1
मुझे खेद है कि यह मेरा पहला योगदान था। मैं इसे ठीक कर दूंगा। प्रतिक्रिया के लिए धन्यवाद
मैथ्यू मार्टिंस जेरोनिमो

3
अक्षम: एक लंबाई के साथ कई बार (लूप परिवर्तन ) for(int i = 0; i < strlen(Name); i++ )कॉल करेगा , यह एक समाधान है। ओ (एन) `समाधान प्रदान करने के लिए केवल 1 कॉल , यदि कोई हो, की आवश्यकता है। अस्पष्ट क्यों इसके बजाय प्रयोग किया जाता है । विचार करेंstrlen(Name)Name[]NO(N*N)strlen(Name)int isize_t ifor(size_t i = 0; i < Name[i]; i++ )
chux -

@chux अधिक पसंदfor (size_t i = 0; Name[i]; i++) { if (Name[i] == '\n') { Name[i] = '\0'; break; } }
melpomene

-1

इसको आजमाओ:

        int remove_cr_lf(char *str)
        {
          int len =0;


          len = strlen(str);

          for(int i=0;i<5;i++)
          {
            if (len>0)
            if (str[len-1] == '\n')
            {
              str[len-1] = 0;
              len--;
            }

            if (len>0)
            if (str[len-1] == '\r')
            {
              str[len-1] = 0;
              len--;
            }
          }

          return 0;
        }

1
len = strlen(str)अतिप्रवाह हो सकता है: strlenरिटर्न size_t, नहीं int। अजीब के साथ क्या हैif (len>0) if (...) स्थिति ? क्या आप इसके बारे में नहीं जानते हैं &&? यदि आप CR / LF के कई अनुगामी उदाहरणों को हटाने जा रहे हैं, तो अपने आप को 5 तक सीमित क्यों करें? सभी को क्यों नहीं हटाया? intजब हमेशा रिटर्न होता है तो फ़ंक्शन का रिटर्न प्रकार क्यों होता है 0? सिर्फ वापस क्यों नहीं void?
melpomene
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.