Fayldagi yangi qatorlarni qanday sanash mumkin, faqat yangi satrlar bo'lgan qatorlarni hisoblamaslik kerakmi?

Kirishni to'g'ri tahlil qilish uchun menda fayllar sonini sanash kerak. Biroq, yangi satrlarni bo'lgan satrlarni hisoblashni xohlamayman. Buning uchun men quyidagi vazifani yaratdim:

int countLinesInFile(char *filename) {
  int newlines = 0;

  if (access(filename,F_OK) != -1)
    error("File not found",0);

  FILE *input = fopen(filename,"r");

  int size = 256 * 4;
  char buffer[size];
  while ((fgets(buffer,sizeof(buffer),input)) != EOF) {
    printf("Read a string");
    if (buffer == "\n")
      continue;
    newlines++;
  }

  fclose(input);
  return newlines;
}

Faylning yuqori qismida quyidagilar mavjud:

#include 
#include 

Dasturni ishga tushirganimda va chiziqlarni sanashga urinib ko'rsangiz, segmentatsiya buzilishi. Valgrinddan foydalanib, quyidagilarni ko'ra olaman:

==6632== Invalid read of size 4
==6632==    at 0x4EA8E6B: fgets (in /usr/lib64/libc-2.24.so)
==6632==    by 0x402219: countLinesInFile (in [executable])
[other information about program, does not seem relevant]
==6632==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==6632== 
==6632== 
==6632== Process terminating with default action of signal 11 (SIGSEGV)
==6632==  Access not within mapped region at address 0x0
==6632==    at 0x4EA8E6B: fgets (in /usr/lib64/libc-2.24.so)
==6632==    by 0x402219: countLinesInFile (in [executable])
[other information about program, does not seem relevant]
==6632==  If you believe this happened as a result of a stack
==6632==  overflow in your program's main thread (unlikely but
==6632==  possible), you can try to increase the size of the
==6632==  main thread stack using the --main-stacksize= flag.
==6632==  The main thread stack size used in this run was 8388608.
==6632== 
==6632== HEAP SUMMARY:
==6632==     in use at exit: 475 bytes in 16 blocks
==6632==   total heap usage: 19 allocs, 3 frees, 3,075 bytes allocated
==6632== 
==6632== LEAK SUMMARY:
==6632==    definitely lost: 0 bytes in 0 blocks
==6632==    indirectly lost: 0 bytes in 0 blocks
==6632==      possibly lost: 0 bytes in 0 blocks
==6632==    still reachable: 475 bytes in 16 blocks
==6632==         suppressed: 0 bytes in 0 blocks
==6632== Rerun with --leak-check=full to see details of leaked memory
==6632== 
==6632== For counts of detected and suppressed errors, rerun with: -v
==6632== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Men "loop" ning boshida "printf" ("Faylni o'qish") degan bir satr qo'yishga urindim. Ushbu kod ijro etilmaydi va o'ylaymanki, bu muammodir. Afsuski, bu muammo nima ekanini bilmayman.

O'qishga harakat qilmoqdaki fayl to'g'ri matnga ega ekanligini tasdiqladi va bo'sh emas.

Ushbu vazifani to'g'ri usulda yaratgan vazifammi? Agar shunday bo'lsa, men qanday muammolarga duch kelmoqdaman? Kelajakda bu muammoni qanday qilib chetlab o'tishim mumkin?

Yangilash: Bu, albatta, menda achinarli xato edi. Men dasturni Valgrind bilan ishlay boshladim, u faylni topa olmaydi degan ma'noni anglatuvchi executable-ning katalogidan foydalanmaydi. Yordamingiz uchun tashakkur.

1
@BLUEPIXY Men fopen chiqdimini tekshirdim, shu faylga "stuff.br" (ochiladigan fayl nomi, men tekshirganim) bir xil katalogda bo'lishiga qaramay "fayl topilmadi", deydi.
qo'shib qo'ydi muallif John Nunley, manba
@BLUEPIXY Ha, u executable bilan bir xil katalogda mavjud. IDE dan foydalanmayapman, men Vim + CMake + Gcc dan foydalanmoqdaman. Foydalanuvchining kiritishidan yangi qatorni olib tashlayapman. Ammo to'liq katalog yo'lini ko'rsataman.
qo'shib qo'ydi muallif John Nunley, manba
fgets EOF kodini qaytarmaydi.
qo'shib qo'ydi muallif BLUEPIXY, manba
Fayl executable fayl bilan bir xil katalogda mavjudmi? IDE da ishlayotganida bu odatda bir xil katalog emas. fayl nomining to'liq yo'lini aniqlab ko'ring. Bundan tashqari, foydalanuvchi nomidan fayl nomini kiritayotgan bo'lsangiz, yangi qatorni o'chirib qo'ydingizmi?
qo'shib qo'ydi muallif BLUEPIXY, manba
Ehtimol, ba'zi tanqidlar noto'g'ri deb o'ylayotgandirsiz, lekin uni tasdiqlashning hech qanday usuli yo'q.
qo'shib qo'ydi muallif BLUEPIXY, manba
Masalan, quyidagi formatga o'ting va uni sinab ko'ring. ls * .br ... ./ a.out stuff.br ... int boshi (int argc, char * argv []) {< kodi ... int count = countLinesInFile (argv [1]);
qo'shib qo'ydi muallif BLUEPIXY, manba
fopen ning qaytib qiymatini tekshirib, boshlang.
qo'shib qo'ydi muallif kaylum, manba
buffer == "\ n" va bu kodni taqqoslashning yo'li emas. strcmp yoki belgilar taqqoslashini ishlatish kerak buffer [0] == ' \ n '
qo'shib qo'ydi muallif kaylum, manba
Agar fayl bu erda bo'lsa, siz (yoki foydalanuvchi/guruh dasturning hech bo'lmaganda sifatida ishlayotganiga) ishonch hosil qilish uchun ruxsatnomalarni tekshiring. Bundan tashqari, access() kerak yoki faqat fopen() qaytarilgan NULL (baribir bajarish kerakmi)?
qo'shib qo'ydi muallif Dmitri, manba

5 javoblar

FILE *input = fopen(filename,"r");

bo'lishi kerak

FILE *input;
input = fopen(filename,"r");

fgets() , yangi yoki EOF-ni qaytarib berishiga ishonmayman. Yangi satrdan oldin harflar bilan o'qishni to'xtatadi va navbatdagi o'qish yangi satrdan so'ng yoki keyingi ketma-ketlikdagi belgilar bo'ladi.

Ehtimol, bir vaqtning o'zida butun faylni o'qiydigan va keyinchalik chiziqlarni ajratadigan ikkita faylni o'qish funktsiyasidan foydalaning. Bundan tashqari, oxirida EOFga ega bo'lmagan matnli faylni ko'rib chiqamiz. Ko'pchilik yo'q

  • Fayl hajmini oling.
  • Barcha faylni ushlab turish uchun buferni ajratish.
  • Barcha faylni buferga o'qing.
  • Tamponni ajrating.

C library function - fgets()
C File I/O and Binary File I/O

2
qo'shib qo'ydi
Ikki qatorli kodda hech qanday qiymat yo'q. fgets() haqida sizning e'tiqodingiz noto'g'ri - xususan, uning uchun joy bo'lmasa, ma'lumotlardagi yangi qatorni o'z ichiga oladi. NUL ko'rsatgichni qaytarib, EOF ni ko'rsatadi. Butun faylni buferga o'qishga hojat yo'q. Ishni uchta sonli (oxirgi belgi, bu belgi, umumiy hisob) va getc() bilan amalga oshirishingiz mumkin.
qo'shib qo'ydi muallif Jonathan Leffler, manba
FILE * input = fopen (filename, "r"); da nima bo'ladi? "Ikkilik fayllarni o'qish funktsiyasidan foydalaning" nima uchun matnli fayl uchun ikkilik fayllarni o'qish uchun kerak?
qo'shib qo'ydi muallif kaylum, manba

EOF emas, balki ikki qator narsalar: oldin fgets NULL kodini qaytaradi. Shunday qilib, vaziyat while (fgets (...)! = NULL) yoki while (fgets (...)) bo'lishi kerak. Ikkinchidan, buffer == "\ n" belgilarga ikki belgini solishtiradi, ya'ni ikki xotira manzillari taqqoslanadi. "\ n" harflari bilan bir xil xotira manziliga ega bo'lish ehtimoli kam. Shuning uchun, belgilarni, ya'ni buffer [0] == '\ n' yoki buffer [0]! = '\ N' bilan solishtiring. Va kodni continue -statement-dan xalos qilish mumkin, deb o'ylayman, shuning uchun kod quyidagicha ko'rinadi:

  while (fgets(buffer,sizeof(buffer),input)) {
    if (buffer[0] != '\n') {
      newlines++;
    }
  }
1
qo'shib qo'ydi
Men buni qildim, lekin bu segfault davom etmoqda. Muammo shundaki, bu birinchi chaqiriq bilan bog'liq.
qo'shib qo'ydi muallif John Nunley, manba

fgets() restricts you to a predefined line length. To get around that, you can use POSIX-standard getline().

Bo'sh satrlarni skanerlashda siz oddiygina "\ n" ga mos keladigan har qanday narsani diskontlashingiz mumkin:

#include 

...

long countLines( const char *filename )
{
    FILE *fp = fopen( filename, "r" );
    if ( fp == NULL )
    {
        return( -1L );
    }

    char *line = NULL;
    size_t bytes = 0UL;
    long lineCount = 0L;

    for ( ;; )
    {
        ssize_t result = getline( &line, &bytes, fp );
        if ( -1 == result )
        {
            break;
        }

        if ( strcmp( line, "\n" ) )
        {
            lineCount++;
        }
    }

    free( line );
    fclose( fp );

    return( lineCount );
}
0
qo'shib qo'ydi

Funktsiya fgets bir nuqta qiymatini qaytaradi yoki noto'g'ri bo'lsa NULL. EOF (odatda, siz uni o'zgartirmaguningizcha) -1 deb belgilangan. Ular hech qachon tenglasha olmaydi, demak siz to'xtab turganingizdan keyin sizni uzoq vaqt chaqirasiz.

0
qo'shib qo'ydi
Afsuski, bu men ishlayotgan loopni boshqaradigan har qanday chiziqni qo'shgan bo'lsam, bu chiqadi. Afsuski, bunday qilmadi. O'ylaymanki, bu birinchi toifalar muvaffaqiyatsizlikka uchraydi.
qo'shib qo'ydi muallif John Nunley, manba
Va EOF bilan bir xil emas NULLni qaytaradi ...
qo'shib qo'ydi muallif Austin Hastings, manba

Sizning oxirgi \ n faylining ofsetini kuzatishingiz kerak, deb o'ylayman va bu \ n == last + 1ning pozitsiyasini oshirmasangiz.

0
qo'shib qo'ydi