কেন "যখন (! ফিউফ (ফাইল))" সবসময় ভুল?


573

আমি ইদানীং প্রচুর পোস্টে লোকেদের মতো ফাইলগুলি পড়ার চেষ্টা করতে দেখেছি:

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

int
main(int argc, char **argv)
{
    char *path = "stdin";
    FILE *fp = argc > 1 ? fopen(path=argv[1], "r") : stdin;

    if( fp == NULL ) {
        perror(path);
        return EXIT_FAILURE;
    }

    while( !feof(fp) ) {  /* THIS IS WRONG */
        /* Read and process data from file… */
    }
    if( fclose(fp) != 0 ) {
        perror(path);
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

এই লুপটিতে কী ভুল?



উত্তর:


453

আমি একটি বিমূর্ত, উচ্চ-স্তরের দৃষ্টিভঙ্গি সরবরাহ করতে চাই।

সমকালীনতা এবং যুগপততা

আই / ও অপারেশন পরিবেশের সাথে যোগাযোগ করে। পরিবেশটি আপনার প্রোগ্রামের অংশ নয় এবং আপনার নিয়ন্ত্রণে নেই। আপনার প্রোগ্রামটির সাথে পরিবেশটি "একইসাথে" উপস্থিত রয়েছে। একই সাথে সব কিছু একই সাথে, "বর্তমান অবস্থা" সম্পর্কে প্রশ্নগুলি বোধগম্য নয়: সমসাময়িক ইভেন্টগুলিতে "একযোগে" কোনও ধারণা নেই। রাষ্ট্রের অনেক বৈশিষ্ট্য একই সাথে অস্তিত্বহীন

আমাকে এটি আরও সুনির্দিষ্ট করে তুলুন: ধরুন আপনি জিজ্ঞাসা করতে চান, "আপনার কাছে আরও ডেটা আছে কি"? আপনি এটি একসাথে ধারক বা আপনার I / O সিস্টেম সম্পর্কে জিজ্ঞাসা করতে পারেন। তবে উত্তরটি সাধারণত অকার্যকর এবং এইভাবে অর্থহীন। সুতরাং যদি ধারকটি "হ্যাঁ" বলে - আপনি পড়ার চেষ্টা করার সময়, এর আর ডেটা নাও থাকতে পারে। একইভাবে, উত্তরটি যদি "না" হয়, আপনি পড়ার চেষ্টা করার সময়, ডেটা উপস্থিত হতে পারে। উপসংহারটি কেবল সেখানে রয়েছে"আমার কাছে ডেটা আছে" এর মতো কোনও সম্পত্তি নেই, কারণ আপনি কোনও সম্ভাব্য উত্তরের প্রতিক্রিয়াতে অর্থপূর্ণভাবে কাজ করতে পারবেন না। (বাফার ইনপুট দিয়ে পরিস্থিতি কিছুটা উন্নত, যেখানে আপনি সম্ভবত "হ্যাঁ, আমার কাছে ডেটা আছে" যা কোনওরকম গ্যারান্টি গঠন করে, তবে আপনাকে এখনও বিপরীত ক্ষেত্রে মোকাবেলা করতে সক্ষম হতে হবে output এবং আউটপুট সহ পরিস্থিতি আমি অবশ্যই বর্ণনা করেছি ঠিক তেমনি খারাপ: আপনি কখনই জানেন না যে ডিস্ক বা সেই নেটওয়ার্ক বাফার পূর্ণ কিনা))

সুতরাং আমরা এই উপসংহারে আসে যে এটা অসম্ভব, এবং সত্য জাতিসংঘে যুক্তিসংগত কোনো I / O সিস্টেম কিনা এটা জিজ্ঞেস করা উচিত, হতে হবে কোনো I / O অপারেশন করা যাবে না। আমরা এটির সাথে যোগাযোগ করতে পারার একমাত্র সম্ভাব্য উপায় (ঠিক তেমনি একটি সমবর্তী ধারক হিসাবে) অপারেশনটি চেষ্টা করা এবং এটি সফল হয়েছে কিনা তা পরীক্ষা করা। সেই মুহুর্তে যেখানে আপনি পরিবেশের সাথে ইন্টারঅ্যাক্ট করেন, তারপরে এবং কেবল তখনই আপনি জানতে পারবেন যে মিথস্ক্রিয়াটি আসলে সম্ভব হয়েছিল কিনা এবং সেই সময়ে আপনাকে অবশ্যই ইন্টারঅ্যাকশন সম্পাদন করতে প্রতিশ্রুতিবদ্ধ হতে হবে। (আপনি যদি এটি করেন তবে এটি একটি "সিঙ্ক্রোনাইজেশন পয়েন্ট"))

ফাইলের শেষে

এখন আমরা ইওএফ এ উঠি। ইওএফ হ'ল প্রতিক্রিয়া যা আপনি চেষ্টা করা আই / ও অপারেশন থেকে পান। এর অর্থ হ'ল আপনি কিছু পড়তে বা লেখার চেষ্টা করছেন, তবে এটি করার সময় আপনি কোনও ডেটা পড়তে বা লিখতে ব্যর্থ হয়েছিলেন এবং পরিবর্তে ইনপুট বা আউটপুটটির শেষের মুখোমুখি হয়েছিল। এটি মূলত সমস্ত আই / ও এপিআই-এর জন্য সত্য, এটি সি স্ট্যান্ডার্ড লাইব্রেরি, সি ++ আইস্ট্রিমেজ বা অন্যান্য লাইব্রেরিই হোক না কেন। যতক্ষণ I / O অপারেশনগুলি সফল হয়, আপনি কেবল ভবিষ্যতে অপারেশনগুলি সফল হবে কিনা তা জানতে পারবেন না । আপনাকে অবশ্যই সর্বদা প্রথমে অপারেশনটি ব্যবহার করে দেখতে হবে এবং তারপরে সাফল্য বা ব্যর্থতার প্রতিক্রিয়া জানাতে হবে।

উদাহরণ

প্রতিটি উদাহরণে, সাবধানে লক্ষ করুন যে আমরা প্রথমে I / O অপারেশনটি চেষ্টা করি এবং তারপরে এটি কার্যকর হলে ফলাফলটি গ্রাস করি। আরও নোট করুন যে আমাদের সর্বদা আই / ও অপারেশনের ফলাফলটি অবশ্যই ব্যবহার করা উচিত, যদিও ফলাফল প্রতিটি উদাহরণে বিভিন্ন আকার এবং আকার নেয়।

  • সি স্টিডিও, একটি ফাইল থেকে পড়ুন:

    for (;;) {
        size_t n = fread(buf, 1, bufsize, infile);
        consume(buf, n);
        if (n < bufsize) { break; }
    }

    আমাদের যে ফলাফলটি ব্যবহার করতে হবে তা হ'ল n, যে উপাদানগুলির সংখ্যা পড়েছিল (যা শূন্যের চেয়ে কম হতে পারে)।

  • সি স্টিডিও scanf,:

    for (int a, b, c; scanf("%d %d %d", &a, &b, &c) == 3; ) {
        consume(a, b, c);
    }

    আমাদের যে ফলাফলটি ব্যবহার করতে হবে তা হ'ল রিটার্ন মান scanf, রূপান্তরিত উপাদানগুলির সংখ্যা।

  • সি ++, আইওস্ট্রিমে ফর্ম্যাট করা নিষ্কাশন:

    for (int n; std::cin >> n; ) {
        consume(n);
    }

    আমাদের যে ফলাফলটি ব্যবহার std::cinকরতে হবে তা হ'ল এটি একটি বুলিয়ান প্রসঙ্গে মূল্যায়ন করা যেতে পারে এবং আমাদের জানায় যে স্ট্রিমটি এখনও good()রাজ্যে রয়েছে কিনা whether

  • সি ++, আইওস্ট্রিমে গেটলাইন:

    for (std::string line; std::getline(std::cin, line); ) {
        consume(line);
    }

    আমাদের অবশ্যই ফলাফলটি আবার ব্যবহার করতে হবে std::cinঠিক আগের মতোই।

  • POSIX, write(2)একটি বাফার ফ্লাশ করতে:

    char const * p = buf;
    ssize_t n = bufsize;
    for (ssize_t k = bufsize; (k = write(fd, p, n)) > 0; p += k, n -= k) {}
    if (n != 0) { /* error, failed to write complete buffer */ }

    আমরা এখানে ফলাফলটি ব্যবহার করি k, লিখিত বাইটের সংখ্যা। এখানে বক্তব্যটি হ'ল রাইটিং অপারেশনের পরে আমরা কত বাইট লিখেছি তা কেবল আমরা জানতে পারি ।

  • POSIX getline()

    char *buffer = NULL;
    size_t bufsiz = 0;
    ssize_t nbytes;
    while ((nbytes = getline(&buffer, &bufsiz, fp)) != -1)
    {
        /* Use nbytes of data in buffer */
    }
    free(buffer);

    আমাদের যে ফলাফলটি ব্যবহার করতে হবে তা হ'ল nbytesনিউলাইন পর্যন্ত বাইট সংখ্যা এবং (বা ফাইলটি যদি নতুন লাইনের সাথে শেষ না হয় তবে ইওএফ) অন্তর্ভুক্ত।

    মনে রাখবেন যে -1কোনও ত্রুটি দেখা দিলে বা এটি ইওএফ পৌঁছায় ফাংশনটি স্পষ্টতই ফিরে আসে (এবং ইওএফ নয়!)।

আপনি লক্ষ্য করতে পারেন যে আমরা খুব কমই আসল শব্দ "ইওএফ" বানান করি। আমরা সাধারণত অন্য কোনও উপায়ে ত্রুটি শর্তটি সনাক্ত করি যা আমাদের কাছে তত্ক্ষণাত্ আকর্ষণীয় (যেমন আমরা যতটা ইচ্ছা I / O করতে চেয়েছি পারফরম্যান্সে ব্যর্থতা)। প্রতিটি উদাহরণে কিছু এপিআই বৈশিষ্ট্য রয়েছে যা আমাদের স্পষ্টভাবে বলতে পারে যে ইওএফ রাষ্ট্রের মুখোমুখি হয়েছে, তবে এটি বাস্তবে কোনও তথ্যের ভয়াবহ উপকারী অংশ নয়। এটি প্রায়শই আমাদের যত্নশীল হওয়ার চেয়ে অনেক বেশি বিশদ। আই / ও সফল হয়েছে কিনা তা কীভাবে গুরুত্বপূর্ণ তা কীভাবে এটি ব্যর্থ হয়েছিল than

  • একটি চূড়ান্ত উদাহরণ যা বাস্তবে ইওএফ রাষ্ট্রকে জিজ্ঞাসা করে: ধরুন আপনার কাছে একটি স্ট্রিং রয়েছে এবং এটি পরীক্ষা করতে চান যে এটি সম্পূর্ণরূপে একটি পূর্ণসংখ্যার প্রতিনিধিত্ব করে, শেষে সাদা অংশ ছাড়া কোনও অতিরিক্ত বিট নেই no সি ++ আইস্ট্রিম ব্যবহার করে এটি এরকম হয়:

    std::string input = "   123   ";   // example
    
    std::istringstream iss(input);
    int value;
    if (iss >> value >> std::ws && iss.get() == EOF) {
        consume(value);
    } else {
        // error, "input" is not parsable as an integer
    }

    আমরা এখানে দুটি ফলাফল ব্যবহার করি। প্রথমটি হ'ল issস্ট্রিম অবজেক্টটি নিজেই পরীক্ষা করে নিন যে ফর্ম্যাটযুক্ত নিষ্কাশন valueসফল হয়েছে। তবে তারপরে, হোয়াইটস্পেস গ্রাস করার পরেও আমরা অন্য আই / ও / অপারেশন iss.get()করি এবং এটি ইওএফ হিসাবে ব্যর্থ হওয়ার প্রত্যাশা করি, যদি পুরো স্ট্রিংটি ইতিমধ্যে ফর্ম্যাট নিষ্কাশন দ্বারা গ্রাস করা হয়ে থাকে।

    সি স্ট্যান্ডার্ড লাইব্রেরিতে আপনি strto*lশেষ পয়েন্টারটি ইনপুট স্ট্রিংয়ের শেষে পৌঁছেছে তা পরীক্ষা করে ফাংশনগুলির সাথে অনুরূপ কিছু অর্জন করতে পারেন ।

উত্তর

while(!feof)এটি ভুল কারণ এটি অপ্রাসঙ্গিক এমন কোনও কিছুর জন্য পরীক্ষা করে যা আপনার জানা প্রয়োজন এমন কোনও পরীক্ষার জন্য ব্যর্থ হয়। ফলস্বরূপ আপনি ভুলের সাথে কোডটি সম্পাদন করছেন যা ধরে নিয়েছে যে এটি সফলভাবে পড়া পড়া ডেটা অ্যাক্সেস করছে, যখন বাস্তবে এটি কখনও ঘটে নি।


34
@ সিয়াপান: আমি সত্য মনে করি না। C99 এবং C11 উভয়ই এটির অনুমতি দেয়।
কেরেক এসবি

11
তবে এএনএসআই সি তা করে না।
CiaPan

3
@ জোনাথনমি: আমি যে কারণগুলির উল্লেখ করেছি তার জন্য এটি খারাপ: আপনি ভবিষ্যতের দিকে তাকাতে পারবেন না। ভবিষ্যতে কী হবে তা আপনি বলতে পারবেন না।
কেরেক এসবি

3
@ জোনাথনমি: হ্যাঁ, এটি যথাযথ হবে যদিও সাধারণত আপনি এই চেকটি অপারেশনের সাথে সংযুক্ত করতে পারেন (যেহেতু বেশিরভাগ আইস্ট্রিমেজ অপারেশনগুলি স্ট্রিম অবজেক্টকে ফিরিয়ে দেয়, যার নিজেই একটি বুলিয়ান রূপান্তর রয়েছে), এবং এইভাবে আপনি স্পষ্ট করে দেন যে আপনি নন প্রত্যাবর্তনের মান অগ্রাহ্য করা।
কেরেক এসবি 21

4
তৃতীয় অনুচ্ছেদটি গ্রহণযোগ্য এবং অত্যন্ত উত্তরের উত্তরের জন্য উল্লেখযোগ্যভাবে বিভ্রান্ত / ভুল c feof()"I / O সিস্টেমের আরও ডেটা আছে কিনা তা জিজ্ঞাসা করে না"। feof()(লিনাক্স) ম্যানপেজ অনুসারে : "স্ট্রিম দ্বারা নির্দেশিত স্ট্রিমের জন্য ফাইলের শেষের সূচকটি পরীক্ষা করে, যদি সেট করা থাকে তবে ননজারো ফিরিয়ে দেয়" " (এছাড়াও, একটি সুস্পষ্ট clearerr()কলই এই সূচকটি পুনরায় সেট করার একমাত্র উপায়); এই ক্ষেত্রে উইলিয়াম পার্সেলের উত্তর আরও ভাল better
আরনে ভোগেল

234

এটি ভুল কারণ (পড়ার ত্রুটির অভাবে) এটি লেখকের প্রত্যাশার চেয়ে লুপটিতে আরও একবার প্রবেশ করে। যদি কোনও পঠন ত্রুটি থাকে তবে লুপটি কখনই শেষ হয় না।

নিম্নলিখিত কোড বিবেচনা করুন:

/* WARNING: demonstration of bad coding technique!! */

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

FILE *Fopen(const char *path, const char *mode);

int main(int argc, char **argv)
{
    FILE *in;
    unsigned count;

    in = argc > 1 ? Fopen(argv[1], "r") : stdin;
    count = 0;

    /* WARNING: this is a bug */
    while( !feof(in) ) {  /* This is WRONG! */
        fgetc(in);
        count++;
    }
    printf("Number of characters read: %u\n", count);
    return EXIT_SUCCESS;
}

FILE * Fopen(const char *path, const char *mode)
{
    FILE *f = fopen(path, mode);
    if( f == NULL ) {
        perror(path);
        exit(EXIT_FAILURE);
    }
    return f;
}

এই প্রোগ্রামটি ধারাবাহিকভাবে ইনপুট স্ট্রিমের অক্ষরের সংখ্যার চেয়ে বড় একটিকে মুদ্রণ করবে (কোনও পঠন ত্রুটি অনুমান করে)। ইনপুট স্ট্রিমটি খালি থাকার ক্ষেত্রে বিবেচনা করুন:

$ ./a.out < /dev/null
Number of characters read: 1

এই ক্ষেত্রে, feof()কোনও ডেটা পড়ার আগে বলা হয়, সুতরাং এটি মিথ্যা প্রত্যাবর্তন করে। লুপটি প্রবেশ করা হয়, fgetc()তাকে বলা হয় (এবং ফিরে আসে EOF), এবং গণনা বৃদ্ধি করা হয়। তারপরে feof()ডাকা হয় এবং সত্য ফিরে আসে, যার ফলে লুপটি বন্ধ হয়ে যায়।

এ জাতীয় সব ক্ষেত্রেই এটি ঘটে থাকে। feof()যতক্ষণ না সত্য ফেরত দেয় না পরে প্রবাহে একটি পঠিত ফাইলের শেষে encounters। এর উদ্দেশ্যটি feof()পরের পঠিত ফাইলের শেষে পৌঁছবে কিনা তা যাচাই করা নয়। এর উদ্দেশ্য feof()হ'ল পঠন ত্রুটির মধ্যে পার্থক্য করা এবং ফাইলটির শেষে পৌঁছে যাওয়া। যদি fread()0 প্রদান করে, আপনার অবশ্যই কোনও ত্রুটির মুখোমুখি হয়েছিল কিনা বা সমস্ত ডেটা গ্রাস হয়েছে কিনা তা স্থির করতে feof/ ব্যবহার করতে হবে ferror। একইভাবে যদি fgetcফিরে আসে EOFfeof()শুধুমাত্র দরকারী পর fread এর শূন্য ফিরে এসেছে বা fgetcফিরে এসেছে EOF। এর আগে, feof()সর্বদা 0 এ ফিরে আসবে।

কল করার আগে সর্বদা একটি পঠনের রিটার্ন মান (যা হয় একটি fread(), বা একটি fscanf(), বা একটি fgetc()) চেক করা প্রয়োজন feof()

আরও খারাপ, কেস পড়ার ক্ষেত্রে ত্রুটি দেখা দেয় সেখানে বিবেচনা করুন। সেক্ষেত্রে, fgetc()আয় EOF, feof()আয় মিথ্যা, এবং লুপ কখনো বন্ধ। যে সমস্ত ক্ষেত্রে while(!feof(p))ব্যবহৃত হয়, লুপের ভিতরে অবশ্যই কমপক্ষে একটি চেক থাকা উচিত ferror(), বা খুব কমপক্ষে অবস্থার পরিবর্তিত হওয়া উচিত while(!feof(p) && !ferror(p))বা অসীম লুপের প্রকৃত সম্ভাবনা রয়েছে, সম্ভবত সমস্ত প্রকার আবর্জনা বানান হিসাবে অবৈধ ডেটা প্রক্রিয়াজাত করা হচ্ছে।

সুতরাং, সংক্ষেপে, যদিও আমি দৃ with়তার সাথে বলতে পারি না যে " while(!feof(f))" লেখার ক্ষেত্রে শব্দার্থগতভাবে সঠিক হতে পারে এমন কোনও পরিস্থিতি কখনও নেই (যদিও পঠনের ত্রুটির অনন্ত লুপ এড়াতে বিরতির সাথে লুপের ভিতরে আরও একটি চেক থাকা আবশ্যক) ) এটি প্রায় সর্বদা ভুল বলে মনে হয়। এমনকি যদি এটির ক্ষেত্রেও কোনও মামলা উত্থাপিত হয় তবে এটি এতটা মূর্খতার সাথে ভুল যে কোডটি লেখার সঠিক উপায় হবে না। যে কোনও কোডটি দেখলে অবিলম্বে দ্বিধা প্রকাশ করে বলা উচিত, "এটি একটি বাগ"। এবং সম্ভবত লেখককে চড় মারুন (লেখক যদি আপনার বস না হন তবে ক্ষেত্রে বিবেচনার পরামর্শ দেওয়া হয়েছে।)


7
নিশ্চিত যে এটি ভুল - তবে এগুলি "কৌতূহলীভাবে কুৎসিত" নয়।
নবার

89
আপনার সঠিক কোডের একটি উদাহরণ যুক্ত করা উচিত, কারণ আমি কল্পনা করেছি যে প্রচুর লোক দ্রুত সমাধানের জন্য এখানে আসবে।
jleahy

6
@ থমাস: আমি কোনও সি ++ বিশেষজ্ঞ নই, তবে আমি বিশ্বাস করি যে ফাইল.ওফ () কার্যকরভাবে একই ফলাফল হিসাবে প্রত্যাবর্তন feof(file) || ferror(file)করবে, তাই এটি খুব আলাদা। তবে এই প্রশ্নটি সি ++ এর জন্য প্রযোজ্য নয়।
উইলিয়াম পার্সেল 26'14

6
@ মি-রিচ যেটি ঠিক তা নয়, কারণ আপনি এখনও ব্যর্থ হওয়া কোনও পড়া প্রক্রিয়া করার চেষ্টা করবেন।
মার্ক রান্সম

4
এটি আসল সঠিক উত্তর। পূর্ববর্তী পড়ার চেষ্টার ফলাফল জানতে ফেফ () ব্যবহার করা হয়। সুতরাং সম্ভবত আপনি এটি আপনার লুপ ব্রেক শর্ত হিসাবে ব্যবহার করতে চান না। +1
জ্যাক

63

না এটা সবসময় ভুল হয় না। যদি আপনার লুপের অবস্থা "যদি আমরা ফাইলের অতীত প্রান্তটি পড়ার চেষ্টা করি না" হয় তবে আপনি ব্যবহার করুন while (!feof(f))। এটি তবে একটি সাধারণ লুপ শর্ত নয় - সাধারণত আপনি অন্য কোনও কিছুর জন্য পরীক্ষা করতে চান (যেমন "আমি আরও পড়তে পারি")। while (!feof(f))ভুল নয়, এটি স্রেফ ভুল ব্যবহার করা হয়েছে


1
আমি অবাক হই ... f = fopen("A:\\bigfile"); while (!feof(f)) { /* remove diskette */ }বা (এটি পরীক্ষা করতে যাচ্ছি)f = fopen(NETWORK_FILE); while (!feof(f)) { /* unplug network cable */ }
পিএমজি

1
@ পিএমজি: যেমনটি বলা হয়েছে, "সাধারণ লুপের শর্ত নয়" হহে। আমার প্রয়োজনের যে কোনও ক্ষেত্রে আমি সত্যিই ভাবতে পারি না, সাধারণত আমি ত্রুটি পরিচালনার ইঙ্গিত দিয়ে "আমি কী চাইছিলাম" সে বিষয়ে আগ্রহী
এরিক

@ পিএমজি: যেমন বলা হয়েছে, আপনি খুব কমই চানwhile(!eof(f))
এরিক

9
আরও সঠিকভাবে, শর্তটি "যখন আমরা ফাইলটির শেষের অংশটি পড়ার চেষ্টা করি নি এবং কোনও পাঠ্য ত্রুটি ছিল না" feofতবে ফাইলটির শেষ সনাক্তকরণ সম্পর্কিত নয়; এটি কোনও ত্রুটির কারণে পাঠ্য সংক্ষিপ্ত ছিল বা ইনপুট শেষ হয়ে গেছে তা নির্ধারণ করার বিষয়ে is
উইলিয়াম পার্সেল

35

feof()যদি কেউ ফাইলের শেষটি পড়ার চেষ্টা করে তবে তা সূচিত করে। এর অর্থ এটির সামান্য ভবিষ্যদ্বাণীমূলক প্রভাব রয়েছে: যদি এটি সত্য হয় তবে আপনি নিশ্চিত যে পরবর্তী ইনপুট ক্রিয়াকলাপটি ব্যর্থ হবে (আপনি পূর্ববর্তীটি বিটিডব্লু ব্যর্থ হয়েছেন তা নিশ্চিত নন), তবে এটি মিথ্যা হলে আপনি পরবর্তী ইনপুট সম্পর্কে নিশ্চিত নন অপারেশন সফল হবে। আরও বেশি, ইনপুট ক্রিয়াকলাপগুলি ফাইলের শেষের চেয়ে অন্য কারণে ব্যর্থ হতে পারে (ফর্ম্যাটড ইনপুটটির জন্য একটি ফর্ম্যাট ত্রুটি, একটি খাঁটি আইও ব্যর্থতা - ডিস্ক ব্যর্থতা, নেটওয়ার্ক টাইমআউট - সমস্ত ইনপুট ধরণের জন্য) তবে এমনকি যদি আপনি ভবিষ্যদ্বাণীপূর্ণ হতে পারেন ফাইলের সমাপ্তি (এবং যে কেউ অ্যাডা বাস্তবায়ন করার চেষ্টা করেছে, যা ভবিষ্যদ্বাণীমূলক, আপনাকে বলবে যে আপনার যদি ফাঁকা স্থানগুলি ছাড়ার প্রয়োজন হয় তবে এটি জটিল হতে পারে, এবং এটি ইন্টারেক্টিভ ডিভাইসে অনাকাঙ্ক্ষিত প্রভাব ফেলেছে - কখনও কখনও পরের ইনপুটটিকে বাধ্য করে আগেরটির হ্যান্ডলিং শুরু করার আগে লাইন),

সুতরাং সি এর সঠিক প্রতিমাটি হ'ল লুপ শর্ত হিসাবে আইও অপারেশন সাফল্যের সাথে লুপ করা, এবং তারপরে ব্যর্থতার কারণটি পরীক্ষা করা। এই ক্ষেত্রে:

while (fgets(line, sizeof(line), file)) {
    /* note that fgets don't strip the terminating \n, checking its
       presence allow to handle lines longer that sizeof(line), not showed here */
    ...
}
if (ferror(file)) {
   /* IO failure */
} else if (feof(file)) {
   /* format error (not possible with fgets, but would be with fscanf) or end of file */
} else {
   /* format error (not possible with fgets, but would be with fscanf) */
}

2
কোনও ফাইলের শেষে পৌঁছানো কোনও ত্রুটি নয়, তাই আমি এই প্রশ্নটিটি প্রশ্ন করি "ইনপুট ক্রিয়াকলাপ ফাইলের শেষের চেয়ে অন্য কারণে ব্যর্থ হতে পারে"।
উইলিয়াম পার্সেল

@ উইলিয়াম পার্সেল, ইওফে পৌঁছানো অবশ্যই ত্রুটি নয়, তবে ইওফের কারণে ইনপুট অপারেশন করতে অক্ষম হওয়াই একটি। এবং সিটিতে একটি ইনপুট অপারেশন ব্যর্থ না হয়ে নির্ভরযোগ্যভাবে ইওফ সনাক্ত করা অসম্ভব।
এপ্রোগ্রামার

গত রাজি elseসঙ্গে সম্ভব নয় sizeof(line) >= 2এবং fgets(line, sizeof(line), file)কিন্তু সম্ভব সঙ্গে আবেগপূর্ণ size <= 0এবং fgets(line, size, file)। এমনকি সঙ্গে সম্ভব sizeof(line) == 1
chux -

1
এই সমস্ত "ভবিষ্যদ্বাণীপূর্ণ মান" কথা ... আমি কখনই সে সম্পর্কে সেভাবে ভাবিনি। আমার দুনিয়ায়, feof(f)কিছুতেই প্রিডিক্ট করে না। এটিতে বলা হয়েছে যে একটি পূর্ববর্তী অপারেশন ফাইলটির শেষের দিকে এসে পৌঁছেছে। বেশিও না কমও না. এবং যদি পূর্ববর্তী কোনও ক্রিয়াকলাপ না ঘটে (সবেমাত্র এটি খোলার জন্য), এটি ফাইলটি শুরুর জন্য খালি থাকলেও ফাইলের শেষের প্রতিবেদন করে না। সুতরাং, উপরের অন্য উত্তরে একযোগী ব্যাখ্যা ব্যতীত, লুপ না করার কোনও কারণ আছে বলে আমি মনে করি না feof(f)
বিটিক্লার

@ এপ্রগ্রামগ্রাম: একটি "স্থায়ী" ইওফের কারণে বা এখনও কোনও ডেটা উপলব্ধ না হওয়ার কারণে শূন্যের ফলস্বরূপ "এন বাইটস অব এন বাইটস" অনুরোধ ত্রুটি নয়। যদিও Feof () নির্ভরযোগ্যভাবে ভবিষ্যদ্বাণী করা অনুরোধগুলি ডেটা দেবে তা ভবিষ্যদ্বাণী করতে পারে না, এটি নির্ভরযোগ্যভাবে ইঙ্গিত করতে পারে যে ভবিষ্যতের অনুরোধগুলি তা করবে না । সম্ভবত একটি স্ট্যাটাস ফাংশন থাকা উচিত যা "ভবিষ্যতের পাঠ্য অনুরোধগুলি সফল হবে" তা বোঝানো উচিত, শব্দার্থক শব্দগুলির সাথে একটি সাধারণ ফাইলের শেষে পড়ার পরে, একটি মানের বাস্তবায়ন বলা উচিত যে ভবিষ্যতের পাঠ্যগুলি কোনও কারণে অনুপস্থিত সফল হওয়ার সম্ভাবনা কম বিশ্বাস করুন তারা পারে
সুপারক্যাট

0

feof()খুব স্বজ্ঞাত নয়। আমার খুব নম্র মতামত অনুসারে, FILEফাইলের শেষের দিকে trueযদি কোনও রিড অপারেশন ফলাফল আসে তবে ফাইলটির শেষের ফাইলটি সেট করা উচিত । পরিবর্তে, আপনাকে প্রতিটি পড়ার ক্রিয়াকলাপের পরে ফাইলের সমাপ্তি পৌঁছেছে কিনা তা ম্যানুয়ালি পরীক্ষা করে দেখতে হবে। উদাহরণস্বরূপ, কোনও টেক্সট ফাইল থেকে এটি পড়লে এরকম কিছু কাজ করবে fgetc():

#include <stdio.h>

int main(int argc, char *argv[])
{
  FILE *in = fopen("testfile.txt", "r");

  while(1) {
    char c = fgetc(in);
    if (feof(in)) break;
    printf("%c", c);
  }

  fclose(in);
  return 0;
}

পরিবর্তে এরকম কিছু কাজ করলে এটি দুর্দান্ত হবে:

#include <stdio.h>

int main(int argc, char *argv[])
{
  FILE *in = fopen("testfile.txt", "r");

  while(!feof(in)) {
    printf("%c", fgetc(in));
  }

  fclose(in);
  return 0;
}

printf("%c", fgetc(in));? এটি অপরিজ্ঞাত আচরণ। fgetc()প্রত্যাবর্তন int, না char
অ্যান্ড্রু হেনেল

আমার কাছে মনে হয় প্রমিত আইডিয়ামটি while( (c = getchar()) != EOF)খুব "" এরকম কিছু "।
উইলিয়াম পার্সেল

while( (c = getchar()) != EOF)জিএনইউ সি 10.1.0 চালিত আমার একটি ডেস্কটপে কাজ করে, তবে আমার রাস্পবেরি পাই 4 জিএনইউ সি 9.3.0 এ চলছে ails আমার আরপিআই 4 এ এটি ফাইলের শেষটি সনাক্ত করে না এবং কেবল চালিয়ে যায়।
স্কট দেগান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.