C फ़ाइल लाइन को लाइन से पढ़ें


184

मैंने एक फ़ाइल से एक पंक्ति पढ़ने के लिए यह फ़ंक्शन लिखा है:

const char *readLine(FILE *file) {

    if (file == NULL) {
        printf("Error: file pointer is null.");
        exit(1);
    }

    int maximumLineLength = 128;
    char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);

    if (lineBuffer == NULL) {
        printf("Error allocating memory for line buffer.");
        exit(1);
    }

    char ch = getc(file);
    int count = 0;

    while ((ch != '\n') && (ch != EOF)) {
        if (count == maximumLineLength) {
            maximumLineLength += 128;
            lineBuffer = realloc(lineBuffer, maximumLineLength);
            if (lineBuffer == NULL) {
                printf("Error reallocating space for line buffer.");
                exit(1);
            }
        }
        lineBuffer[count] = ch;
        count++;

        ch = getc(file);
    }

    lineBuffer[count] = '\0';
    char line[count + 1];
    strncpy(line, lineBuffer, (count + 1));
    free(lineBuffer);
    const char *constLine = line;
    return constLine;
}

फ़ंक्शन फ़ाइल को सही ढंग से पढ़ता है, और प्रिंटफ़ का उपयोग करके मैं देखता हूं कि कॉन्स्टेलिन स्ट्रिंग को सही तरीके से पढ़ा गया।

हालाँकि, अगर मैं फ़ंक्शन का उपयोग करता हूं जैसे कि:

while (!feof(myFile)) {
    const char *line = readLine(myFile);
    printf("%s\n", line);
}

प्रिंटफ जिबरिश का उत्पादन करता है। क्यों?


के fgetsबजाय का उपयोग करें fgetc। आप लाइन द्वारा लाइन के बजाय चरित्र द्वारा चरित्र पढ़ रहे हैं।
शिव

3
ध्यान दें कि getline()POSIX 2008 का एक हिस्सा है। इसके बिना POSIX जैसे प्लेटफॉर्म हो सकते हैं, खासकर यदि वे POSIX 2008 के बाकी हिस्सों का समर्थन नहीं करते हैं, लेकिन POSIX सिस्टम की दुनिया के भीतर, getline()इन दिनों बहुत पोर्टेबल है।
जोनाथन

जवाबों:


305

यदि आपका कार्य लाइन-बाय-लाइन रीडिंग फ़ंक्शन का आविष्कार करना नहीं है, लेकिन बस फ़ाइल लाइन-बाय-लाइन पढ़ने के लिए, आप getline()फ़ंक्शन को शामिल करते हुए एक विशिष्ट कोड स्निपेट का उपयोग कर सकते हैं ( यहां मैनुअल पेज देखें ):

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

int main(void)
{
    FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;

    fp = fopen("/etc/motd", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    while ((read = getline(&line, &len, fp)) != -1) {
        printf("Retrieved line of length %zu:\n", read);
        printf("%s", line);
    }

    fclose(fp);
    if (line)
        free(line);
    exit(EXIT_SUCCESS);
}

83
वह पोर्टेबल नहीं है।
जेरेमीप

16
अधिक सटीक रूप से, यह getlineGNU libc, यानी लिनक्स के लिए विशिष्ट है। हालाँकि, यदि आशय लाइन-रीडिंग फ़ंक्शन का है (जैसा कि C सीखने के विपरीत है), वेब पर कई सार्वजनिक डोमेन लाइन-रीडिंग फ़ंक्शन उपलब्ध हैं।
गिलेस एसओ- बुराई को रोकना '

11
मुझे ऐसा क्यों करना चाहिए? मैनुअल पढ़ें, प्रत्येक कॉल पर बफर को फिर से जोड़ा जाता है, फिर इसे अंत में मुक्त किया जाना चाहिए।
mbaitoff

29
if(line)जांच ज़रूरत से ज़्यादा है। कॉलिंग free(NULL)अनिवार्य रूप से नो-ऑप है।
अरोठ

50
उन लोगों के लिए जिन्होंने कहा कि यह गेटलाइन GNU लिबास के लिए विशिष्ट है, "गेटलाइन () और गेटडेलिम (दोनों) मूल रूप से GNU एक्सटेंशन थे। उन्हें POSIX.1-2008 में मानकीकृत किया गया था।"
विलकिल07

37
FILE* filePointer;
int bufferLength = 255;
char buffer[bufferLength];

filePointer = fopen("file.txt", "r");

while(fgets(buffer, bufferLength, filePointer)) {
    printf("%s\n", buffer);
}

fclose(filePointer);

मेरे लिए यह अगले के साथ प्रत्येक पंक्ति को अधिलेखित करने का परिणाम है। उपरोक्त उत्तर के आधार पर यह प्रश्न देखें ।
सीज़र कोबुज़

5
क्यों डाली (FILE*) fp? fpपहले से ही नहीं है FILE *और यह भी fopen()एक रिटर्न FILE *?
लेखाकार

1
यदि आप लाइनों के साथ एक निश्चित लंबाई तक सीमित हैं, तो यह सबसे अच्छा जवाब है। अन्यथा उपयोग getlineकरना एक अच्छा विकल्प है। मैं मानता हूं कि FILE *कलाकार अनावश्यक है।
Theicfire

मैं संयुक्त राष्ट्र-आवश्यक डाली हटा दिया, बफर लंबाई के लिए एक चर जोड़ा गया है और बदल fpकरने के लिए filePointerऔर अधिक स्पष्टता के लिए।
रॉब

21

अपने readLineफ़ंक्शन में, आप एक पॉइंटर को lineसरणी पर लौटाते हैं (सख्ती से बोलना, इसके पहले चरित्र के लिए एक पॉइंटर, लेकिन अंतर यहां अप्रासंगिक है)। चूंकि यह एक स्वचालित चर (यानी, यह "स्टैक पर" है), फ़ंक्शन के वापस आने पर मेमोरी को पुनः प्राप्त किया जाता है। आप अस्पष्ट देखते हैं क्योंकि printfस्टैक पर अपना सामान रखा है।

आपको फ़ंक्शन से एक गतिशील रूप से आवंटित बफर वापस करने की आवश्यकता है। आपके पास पहले से ही एक है, यह है lineBuffer; आपको बस इसे वांछित लंबाई तक काट देना है।

    lineBuffer[count] = '\0';
    realloc(lineBuffer, count + 1);
    return lineBuffer;
}

जोड़ा गया (टिप्पणी में अनुवर्ती प्रश्न का जवाब): readLineलाइन बनाने वाले पात्रों के लिए एक संकेतक लौटाता है। यह पॉइंटर है जिसे आपको लाइन की सामग्री के साथ काम करने की आवश्यकता है। यह भी है कि freeजब आप इन वर्णों द्वारा ली गई मेमोरी का उपयोग करके समाप्त कर लेते हैं तो आपको पास होना चाहिए । यहां बताया गया है कि आप readLineफ़ंक्शन का उपयोग कैसे कर सकते हैं :

char *line = readLine(file);
printf("LOG: read a line: %s\n", line);
if (strchr(line, 'a')) { puts("The line contains an a"); }
/* etc. */
free(line);
/* After this point, the memory allocated for the line has been reclaimed.
   You can't use the value of `line` again (though you can assign a new value
   to the `line` variable if you want). */

@Iron: मैंने अपने उत्तर में कुछ जोड़ा है, लेकिन मुझे यकीन नहीं है कि आपकी कठिनाई क्या है इसलिए यह निशान से दूर हो सकता है।
गिलेस एसओ- बुराई को रोकना '

@ भारतीय: जवाब है कि आप इसे मुक्त नहीं करते हैं। आप दस्तावेज़ (एपीआई प्रलेखन में) तथ्य यह है कि लौटा हुआ बफर Malloc'd है ansd कॉलर द्वारा मुक्त किया जाना चाहिए। फिर जो लोग आपके रीडलाइन फ़ंक्शन का उपयोग करेंगे (उम्मीद है!) उस स्निपेट के समान कोड लिखेंगे जिसे गिल्स ने अपने उत्तर में जोड़ा है।
जेरेमीप

15
//open and get the file handle
FILE* fh;
fopen_s(&fh, filename, "r");

//check if file exists
if (fh == NULL){
    printf("file does not exists %s", filename);
    return 0;
}


//read line by line
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, fh) != NULL)  {
    printf(line);
}
free(line);    // dont forget to free heap memory

1
इस कोड के साथ कुछ समस्याएं हैं: fopen_sकोड को असंगत बना देता है। printfप्रारूप विनिर्देशकों की तलाश करेंगे और प्रतिशत संकेत नहीं छापेंगे और निम्न वर्ण (ओं) के रूप में वे हैं । अशक्त बाइट्स शेष पंक्ति के सभी वर्णों को गायब कर देंगे। (मुझे मत बताओ नल बाइट्स नहीं हो सकता!)
हैगेलो

और वैसे, आप समस्या का समाधान नहीं करते हैं। ओपी का वर्णन है कि उनके कार्य का प्रतिफल गायब हो जाता है। मैं आपको इस समस्या को संबोधित नहीं करता हूं।
हैगेलो

@ हर्टली मुझे पता है कि यह एक पुरानी टिप्पणी है, लेकिन मैं इसे जोड़ रहा हूं ताकि कोई व्यक्ति उसकी टिप्पणी को न पढ़े और लूप में मुक्त करने की कोशिश करे। लूप शुरू होने से पहले लाइन के लिए मेमोरी केवल एक बार आवंटित की जाती है, इसलिए यह लूप के समाप्त होने के बाद केवल एक बार फ्री होना चाहिए। यदि आप लूप के अंदर फ्रीजिंग लाइन की कोशिश करते हैं, तो आपको अप्रत्याशित परिणाम मिलेंगे। इस बात पर निर्भर करता है कि फ्री पॉइंटर (पॉइंटर) कैसे व्यवहार करता है यदि यह सिर्फ मेमोरी को डील करता है और पुराने स्थान पर पॉइंटर्स को इंगित करता है तो कोड काम कर सकता है। यदि यह पॉइंटर को एक और मान प्रदान करता है तो आप मेमोरी के एक अलग सेक्शन को ओवरराइट कर देंगे।
3

2
प्रिंटफ (लाइन) गलत है! यह मत करो। यह आपके कोड को एक स्ट्रिंग प्रारूप भेद्यता के लिए खोलता है जहां आप मुद्रित किए जा रहे सामान के माध्यम से मेमोरी में सीधे स्वतंत्र रूप से पढ़ / लिख सकते हैं। अगर मुझे फाइल में% n /% p डालना था और पॉइंटर को मेमोरी में एक पते पर वापस भेजना था (फाइल से स्ट्रिंग में) जिसे मैंने नियंत्रित किया था, मैं उस कोड को निष्पादित कर सकता था।
ऑक्सागैस्ट

10

readLine() स्थानीय चर के लिए सूचक लौटाता है, जो अपरिभाषित व्यवहार का कारण बनता है।

अपने आस-पास पाने के लिए:

  1. कॉलर फ़ंक्शन में चर बनाएं और इसके पते को पास करें readLine()
  2. मेमोरी का lineउपयोग करने के लिए आवंटित करें malloc()- इस मामले lineमें लगातार रहेगा
  3. वैश्विक चर का उपयोग करें, हालांकि यह आमतौर पर एक बुरा अभ्यास है


4

उदाहरण के साथ कुछ चीजें गलत हैं:

  • आप अपने प्रिंटआउट में \ n जोड़ना भूल गए। साथ ही एरर मैसेजेस को स्टैडर पर जाना चाहिएfprintf(stderr, ....
  • (एक बड़ी बात नहीं है) fgetc()बल्कि के बजाय का उपयोग करने पर विचार करें getc()getc()एक मैक्रो है, fgetc()एक उचित कार्य है
  • getc()intइसलिए रिटर्न को ए chघोषित किया जाना चाहिए int। यह महत्वपूर्ण है क्योंकि इसकी तुलना EOFसही ढंग से की जाएगी। कुछ 8 बिट चरित्र सेट 0xFFएक वैध चरित्र के रूप में उपयोग करते हैं (ISO-LATIN-1 एक उदाहरण होगा) और EOFजो -1 है, 0xFFअगर एक को सौंपा जाएगा char
  • लाइन पर एक संभावित बफर अतिप्रवाह है

    lineBuffer[count] = '\0';

    यदि रेखा बिल्कुल 128 वर्ण लंबी है, countतो उस बिंदु पर 128 है जो निष्पादित होती है।

  • जैसा कि अन्य ने बताया है, lineस्थानीय रूप से घोषित सरणी है। आप इसे एक पॉइंटर नहीं लौटा सकते।

  • strncpy(count + 1)ज्यादा से ज्यादा कॉपी करेंगे count + 1पात्रों लेकिन अगर यह हिट समाप्त होगा '\0' क्योंकि आप सेट lineBuffer[count]करने के लिए '\0'आप जानते हैं कि यह करने के लिए मिल कभी नहीं होगा count + 1। हालाँकि, यदि ऐसा किया गया, तो यह समाप्त नहीं होगा '\0', इसलिए आपको इसे करने की आवश्यकता है। आप अक्सर निम्नलिखित जैसे कुछ देखते हैं:

    char buffer [BUFFER_SIZE];
    strncpy(buffer, sourceString, BUFFER_SIZE - 1);
    buffer[BUFFER_SIZE - 1] = '\0';
  • यदि आपको malloc()लौटने के लिए एक पंक्ति है (आपके स्थानीय charसरणी के स्थान पर ), तो आपका रिटर्न प्रकार होना चाहिए char*- ड्रॉप const


2
void readLine(FILE* file, char* line, int limit)
{
    int i;
    int read;

    read = fread(line, sizeof(char), limit, file);
    line[read] = '\0';

    for(i = 0; i <= read;i++)
    {
        if('\0' == line[i] || '\n' == line[i] || '\r' == line[i])
        {
            line[i] = '\0';
            break;
        }
    }

    if(i != read)
    {
        fseek(file, i - read + 1, SEEK_CUR);
    }
}

और इसका क्या?


2

यहाँ मेरे कई घंटे हैं ... लाइन द्वारा पूरी फ़ाइल लाइन पढ़ना।

char * readline(FILE *fp, char *buffer)
{
    int ch;
    int i = 0;
    size_t buff_len = 0;

    buffer = malloc(buff_len + 1);
    if (!buffer) return NULL;  // Out of memory

    while ((ch = fgetc(fp)) != '\n' && ch != EOF)
    {
        buff_len++;
        void *tmp = realloc(buffer, buff_len + 1);
        if (tmp == NULL)
        {
            free(buffer);
            return NULL; // Out of memory
        }
        buffer = tmp;

        buffer[i] = (char) ch;
        i++;
    }
    buffer[i] = '\0';

    // Detect end
    if (ch == EOF && (i == 0 || ferror(fp)))
    {
        free(buffer);
        return NULL;
    }
    return buffer;
}

void lineByline(FILE * file){
char *s;
while ((s = readline(file, 0)) != NULL)
{
    puts(s);
    free(s);
    printf("\n");
}
}

int main()
{
    char *fileName = "input-1.txt";
    FILE* file = fopen(fileName, "r");
    lineByline(file);
    return 0;
}

1
आप fgetcइसके बजाय क्यों उपयोग कर रहे हैं fgets?
Theicfire

1
const char *readLine(FILE *file, char* line) {

    if (file == NULL) {
        printf("Error: file pointer is null.");
        exit(1);
    }

    int maximumLineLength = 128;
    char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);

    if (lineBuffer == NULL) {
        printf("Error allocating memory for line buffer.");
        exit(1);
    }

    char ch = getc(file);
    int count = 0;

    while ((ch != '\n') && (ch != EOF)) {
        if (count == maximumLineLength) {
            maximumLineLength += 128;
            lineBuffer = realloc(lineBuffer, maximumLineLength);
            if (lineBuffer == NULL) {
                printf("Error reallocating space for line buffer.");
                exit(1);
            }
        }
        lineBuffer[count] = ch;
        count++;

        ch = getc(file);
    }

    lineBuffer[count] = '\0';
    char line[count + 1];
    strncpy(line, lineBuffer, (count + 1));
    free(lineBuffer);
    return line;

}


char linebuffer[256];
while (!feof(myFile)) {
    const char *line = readLine(myFile, linebuffer);
    printf("%s\n", line);
}

ध्यान दें कि 'लाइन' वेरिएबल को कॉलिंग फंक्शन में घोषित किया जाता है और फिर पास किया जाता है, इसलिए आपका readLineफ़ंक्शन पूर्वनिर्धारित बफर को भरता है और इसे वापस लौटाता है। इस तरह से ज्यादातर सी लाइब्रेरीज़ काम करती हैं।

ऐसे अन्य तरीके हैं, जिनसे मैं अवगत हूं:

  • char line[]स्थैतिक के रूप में परिभाषित ( static char line[MAX_LINE_LENGTH] -> यह समारोह से लौटने के बाद इसका मूल्य होगा)। -> खराब है, फ़ंक्शन पुन: नहीं है, और दौड़ की स्थिति हो सकती है -> यदि आप इसे दो थ्रेड्स से दो बार कॉल करते हैं, तो यह परिणाम को अधिलेखित कर देगा
  • malloc()char लाइन [], और कॉलिंग फ़ंक्शंस में इसे mallocफ्री करें -> बहुत अधिक महंगी s, और, बफर को किसी अन्य फ़ंक्शन से मुक्त करने की जिम्मेदारी सौंपते हुए (सबसे सुरुचिपूर्ण समाधान कॉल करने के लिए mallocऔर freeउसी फ़ंक्शन में किसी भी बफ़र्स पर)

Btw, से 'स्पष्ट' कास्टिंग char*के लिए const char*अनावश्यक है।

btw2, लाइनबफ़र की कोई आवश्यकता नहीं है malloc(), बस इसे परिभाषित करें char lineBuffer[128], इसलिए आपको इसे मुक्त करने की आवश्यकता नहीं है

btw3 'डायनेमिक साइज़ स्टैक एरेज़' (एरे को परिभाषित करते हुए char arrayName[some_nonconstant_variable]) का उपयोग नहीं करते हैं, यदि आप वास्तव में नहीं जानते कि आप क्या कर रहे हैं, तो यह केवल C99 में काम करता है।


1
ध्यान दें कि 'लाइन' वेरिएबल को कॉलिंग फंक्शन में घोषित किया जाता है और फिर पास किया जाता है, - आपको शायद तब फंक्शन में लाइन की लोकल डिक्लेरेशन डिलीट करनी चाहिए। इसके अलावा, आपको फ़ंक्शन को यह बताने की आवश्यकता है कि आप कितने लंबे समय से बफर पास कर रहे हैं और उन लाइनों को संभालने की रणनीति के बारे में सोचें जो आपके द्वारा पास किए जाने वाले बफर के लिए बहुत लंबी हैं।
जेरेमीप

1

आपको एक पंक्ति पढ़ने के लिए एएनएसआई कार्यों का उपयोग करना चाहिए, जैसे। fgets। कॉल करने के बाद आपको कॉलिंग के संदर्भ में मुफ्त () चाहिए, जैसे:

...
const char *entirecontent=readLine(myFile);
puts(entirecontent);
free(entirecontent);
...

const char *readLine(FILE *file)
{
  char *lineBuffer=calloc(1,1), line[128];

  if ( !file || !lineBuffer )
  {
    fprintf(stderr,"an ErrorNo 1: ...");
    exit(1);
  }

  for(; fgets(line,sizeof line,file) ; strcat(lineBuffer,line) )
  {
    if( strchr(line,'\n') ) *strchr(line,'\n')=0;
    lineBuffer=realloc(lineBuffer,strlen(lineBuffer)+strlen(line)+1);
    if( !lineBuffer )
    {
      fprintf(stderr,"an ErrorNo 2: ...");
      exit(2);
    }
  }
  return lineBuffer;
}

1

किसी फ़ाइल से सामग्री पढ़ने, और प्राप्त करने की विधि लागू करें (input1.txt)

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

void testGetFile() {
    // open file
    FILE *fp = fopen("input1.txt", "r");
    size_t len = 255;
    // need malloc memory for line, if not, segmentation fault error will occurred.
    char *line = malloc(sizeof(char) * len);
    // check if file exist (and you can open it) or not
    if (fp == NULL) {
        printf("can open file input1.txt!");
        return;
    }
    while(fgets(line, len, fp) != NULL) {
        printf("%s\n", line);
    }
    free(line);
}

उममीद है कि इससे मदद मिलेगी। हैप्पी कोडिंग!


0

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

const char* func x(){
    char line[100];
    return (const char*) line; //illegal
}

इससे बचने के लिए, आप या तो मेमोरी के लिए एक पॉइंटर लौटाते हैं जो ढेर उदाहरण पर रहता है। लाइनबफ़र और यह उपयोगकर्ता की जिम्मेदारी होनी चाहिए कि वह मुफ्त कॉल करे () जब उसके साथ ऐसा किया जाए। वैकल्पिक रूप से आप उपयोगकर्ता को एक तर्क के रूप में पास करने के लिए कह सकते हैं एक स्मृति पता जिस पर लाइन सामग्री लिखना है।


अवैध और अपरिभाषित व्यवहार के बीच एक अंतर है ^ ^।
फोंग

0

मुझे ग्राउंड 0 से एक कोड चाहिए, इसलिए मैंने डिक्शनरी की शब्द पंक्ति की सामग्री को लाइन से पढ़ने के लिए ऐसा किया।

char temp_str [20]; // आप अपनी आवश्यकताओं के अनुसार बफर आकार बदल सकते हैं और एक फ़ाइल में एक एकल पंक्ति की लंबाई।

ध्यान दें कि मैंने प्रत्येक बार जब मैंने लाइन पढ़ी है, तो मैं रिक्त वर्ण के साथ बफर को आरंभीकृत कर लिया है। यह फ़ंक्शन स्वचालित हो सकता है लेकिन चूंकि मुझे संकल्पना के प्रमाण की आवश्यकता है और बाइट द्वारा एक प्रोग्राम डिज़ाइन करना चाहते हैं।

#include<stdio.h>

int main()
{
int i;
char temp_ch;
FILE *fp=fopen("data.txt","r");
while(temp_ch!=EOF)
{
 i=0;
  char temp_str[20]={'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
while(temp_ch!='\n')
{
  temp_ch=fgetc(fp);
  temp_str[i]=temp_ch;
  i++;
}
if(temp_ch=='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
}
printf("%s",temp_str);
}
return 0;
}

यदि आपके ब्रैकेट सही स्थानों पर हैं, तो आपका कार्यक्रम काम करेगा;) जैसेint main() {
dylnmc

संयोग से, आपको सभी 20 '0' निर्दिष्ट करने की आवश्यकता नहीं है। आप बस लिख सकते हैं: codechar temp_str [20] = {'\ 0'}; code c स्वचालित रूप से प्रत्येक स्लॉट को एक शून्य टर्मिनेटर के साथ भर देगा क्योंकि जिस तरह से सरणी घोषणाएं काम करती हैं, यदि कोई सरणी कम तत्वों के साथ आरंभीकृत होती है जिसमें सरणी शामिल है, तो अंतिम तत्व शेष तत्वों को भर देगा।
एलानिएन

मेरा मानना ​​है कि char temp_str[20] = {0}अशक्त टर्मिनेटर के साथ पूरे चरित्र सरणी को भी भरता है।
थू येन तुन

0

खरोंच से मेरा कार्यान्वयन:

FILE *pFile = fopen(your_file_path, "r");
int nbytes = 1024;
char *line = (char *) malloc(nbytes);
char *buf = (char *) malloc(nbytes);

size_t bytes_read;
int linesize = 0;
while (fgets(buf, nbytes, pFile) != NULL) {
    bytes_read = strlen(buf);
    // if line length larger than size of line buffer
    if (linesize + bytes_read > nbytes) {
        char *tmp = line;
        nbytes += nbytes / 2;
        line = (char *) malloc(nbytes);
        memcpy(line, tmp, linesize);
        free(tmp);
    }
    memcpy(line + linesize, buf, bytes_read);
    linesize += bytes_read;

    if (feof(pFile) || buf[bytes_read-1] == '\n') {
        handle_line(line);
        linesize = 0;
        memset(line, '\0', nbytes);
    }
}

free(buf);
free(line);

आप ढेर के बजाय ढेर (मालॉक) का उपयोग क्यों कर रहे हैं? ऐसा लगता है fgetsकि इसके साथ एक सरल स्टैक आधारित समाधान का उपयोग किया जा सकता है।
Theicfire

0

getdelimMsvc, clang, gcc के माध्यम से पारित एक पोर्टेबल और सामान्य फ़ंक्शन प्रदान करें ।

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

ssize_t
portabl_getdelim(char ** restrict linep,
                 size_t * restrict linecapp,
                 int delimiter,
                 FILE * restrict stream) {
    if (0 == *linep) {
        *linecapp = 8;
        *linep = malloc(*linecapp);
        if (0 == *linep) {
            return EOF;
        }
    }

    ssize_t linelen = 0;
    int c = 0;
    char *p = *linep;

    while (EOF != (c = fgetc(stream))) {
        if (linelen == (ssize_t) *linecapp - 1) {
            *linecapp <<= 1;
            char *p1 = realloc(*linep, *linecapp);
            if (0 == *p1) {
                return EOF;
            }
            p = p1 + linelen;
        }
        *p++ = c;
        linelen++;

        if (delimiter == c) {
            *p = 0;
            return linelen;
        }
    }
    return EOF == c ? EOF : linelen;
}


int
main(int argc, char **argv) {
    const char *filename = "/a/b/c.c";
    FILE *file = fopen(filename, "r");
    if (!file) {
        perror(filename);
        return 1;
    }

    char *line = 0;
    size_t linecap = 0;
    ssize_t linelen;

    while (0 < (linelen = portabl_getdelim(&line, &linecap, '\n', file))) {
        fwrite(line, linelen, 1, stdout);
    }
    if (line) {
        free(line);
    }
    fclose(file);   

    return 0;
}

जब fgetsमौजूद है तो ऐसा क्यों करते हैं ?
Theicfire

क्या रेखा रेखाओं को अनुकूलित कर सकती है या वर्तमान लाइनों के बारे में क्या कर सकती है?
南山 南山

getdelimअनुकूलित सीमांकक के लिए अनुमति देता है। इसके अलावा, मैं नोटिस करता हूं कि एक लाइन की लंबाई सीमा नहीं है - इस मामले में आप स्टैक का उपयोग कर सकते हैं getline। (दोनों यहाँ वर्णित: man7.org/linux/man-pages/man3/getline.3.html )
theicfire

क्या आप सिर्फ लिनक्स के बारे में बात करते हैं, सवाल यह है कि सी में लाइन कैसे पढ़ें, है ना?
南山 竹

यह किसी भी मानक c कार्यान्वयन के लिए काम करता है ( getdelimऔर getlinePOSIX.1-2008 में मानकीकृत किया गया था, इस पृष्ठ पर किसी और व्यक्ति का उल्लेख है)। fgetsमानक c भी है, और लिनक्स विशिष्ट नहीं है
Theicfire
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.