Saya menulis fungsi ini untuk membaca baris dari file:
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;
}
Fungsi membaca file dengan benar, dan menggunakan printf saya melihat bahwa string constLine juga bisa dibaca dengan benar.
Namun, jika saya menggunakan fungsi misalnya seperti ini:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s\n", line);
}
printf menampilkan omong kosong. Mengapa?
fgets
sebagai gantifgetc
. Anda membaca karakter demi karakter, bukannya baris demi baris.getline()
adalah bagian dari POSIX 2008. Mungkin ada platform seperti POSIX tanpanya, terutama jika mereka tidak mendukung sisa POSIX 2008, tetapi dalam dunia sistem POSIX,getline()
cukup portabel saat ini.Jawaban:
Jika tugas Anda bukan untuk menciptakan fungsi membaca baris demi baris, tetapi hanya untuk membaca file baris demi baris, Anda dapat menggunakan potongan kode khas yang melibatkan
getline()
fungsi (lihat halaman manual di sini ):sumber
getline
khusus untuk GNU libc, yaitu ke Linux. Namun, jika tujuannya adalah untuk memiliki fungsi membaca garis (sebagai lawan dari belajar C), ada beberapa fungsi membaca garis domain publik yang tersedia di web.if(line)
check adalah berlebihan. Memanggilfree(NULL)
pada dasarnya adalah larangan.sumber
(FILE*) fp
? Bukankahfp
sudahFILE *
dan jugafopen()
mengembalikanFILE *
?getline
adalah alternatif yang baik. Saya setuju paraFILE *
pemeran tidak perlu.fp
menjadifilePointer
lebih jelas.Dalam
readLine
fungsi Anda, Anda mengembalikan pointer keline
array (Sebenarnya, pointer ke karakter pertama, tetapi perbedaannya tidak relevan di sini). Karena ini adalah variabel otomatis (yaitu, "ada di tumpukan"), memori tersebut akan diperoleh kembali saat fungsi kembali. Anda melihat omong kosong karenaprintf
telah meletakkan barang-barangnya sendiri di tumpukan.Anda perlu mengembalikan buffer yang dialokasikan secara dinamis dari fungsi. Anda sudah memilikinya, itu
lineBuffer
; yang harus Anda lakukan adalah memotongnya sesuai panjang yang diinginkan.TAMBAH (respons terhadap pertanyaan tindak lanjut dalam komentar):
readLine
mengembalikan penunjuk ke karakter yang membentuk garis. Pointer ini adalah apa yang Anda butuhkan untuk bekerja dengan isi baris. Ini juga yang harus Anda lewatifree
ketika Anda selesai menggunakan memori yang diambil oleh karakter-karakter ini. Inilah cara Anda menggunakanreadLine
fungsi ini:sumber
sumber
fopen_s
membuat kode tidak dapat diakses.printf
akan mencari penentu format dan tidak mencetak tanda persen dan karakter berikut seperti apa adanya . Null byte akan membuat semua karakter di sisa baris menghilang. (Jangan bilang byte nol tidak bisa terjadi!)readLine()
mengembalikan pointer ke variabel lokal, yang menyebabkan perilaku tidak terdefinisi.Untuk berkeliling Anda bisa:
readLine()
line
menggunakanmalloc()
- dalam hal iniline
akan tetap adasumber
Gunakan
fgets()
untuk membaca baris dari pegangan file.sumber
Beberapa hal salah dengan contoh:
fprintf(stderr, ....
fgetc()
daripadagetc()
.getc()
adalah makro,fgetc()
adalah fungsi yang tepatgetc()
mengembalikan suatuint
sehinggach
harus dinyatakan sebagaiint
. Ini penting karena perbandingan denganEOF
akan ditangani dengan benar. Beberapa set karakter 8 bit digunakan0xFF
sebagai karakter yang valid (ISO-LATIN-1 akan menjadi contoh) danEOF
yang -1, akan0xFF
jika ditugaskan kechar
.Ada potensi buffer overflow di baris
Jika panjang baris tepat 128 karakter,
count
berarti 128 pada titik yang dieksekusi.Seperti yang telah ditunjukkan orang lain,
line
adalah array yang dinyatakan secara lokal. Anda tidak dapat mengembalikan pointer ke sana.strncpy(count + 1)
akan menyalin palingcount + 1
karakter tetapi akan berakhir jika hits'\0'
Karena Anda mengaturlineBuffer[count]
untuk'\0'
Anda tahu itu tidak akan pernah sampai kecount + 1
. Namun, jika itu terjadi, itu tidak akan mengakhiri'\0'
, jadi Anda perlu melakukannya. Anda sering melihat sesuatu seperti berikut:jika Anda
malloc()
ingin mengembalikan sebuah baris (sebagai penggantichar
array lokal Anda ), jenis return Anda seharusnyachar*
- drop theconst
.sumber
bagaimana dengan yang ini?
sumber
Inilah beberapa jam saya ... Membaca seluruh file baris demi baris.
sumber
fgetc
bukanfgets
?perhatikan bahwa variabel 'line' dideklarasikan dalam fungsi panggilan dan kemudian diteruskan, jadi
readLine
fungsi Anda mengisi buffer yang telah ditentukan dan mengembalikannya. Ini adalah cara sebagian besar perpustakaan C bekerja.Ada beberapa cara lain, yang saya ketahui:
char line[]
sebagai statis (static char line[MAX_LINE_LENGTH]
-> itu akan menahan nilainya SETELAH kembali dari fungsi). -> buruk, fungsinya tidak reentrant, dan kondisi balapan dapat terjadi -> jika Anda menyebutnya dua kali dari dua utas, itu akan menimpa hasilnyamalloc()
ing the char line [], dan membebaskannya dalam fungsi panggil -> terlalu banyak yang mahalmalloc
, dan, mendelegasikan tanggung jawab untuk membebaskan buffer ke fungsi lain (solusi paling elegan adalah memanggilmalloc
danfree
pada setiap buffer dalam fungsi yang sama)btw, casting 'eksplisit' dari
char*
toconst char*
redundant.btw2, tidak perlu ke
malloc()
lineBuffer, cukup tentukan sajachar lineBuffer[128]
, jadi Anda tidak perlu membebaskannyabtw3 tidak menggunakan 'array stack ukuran dinamis' (mendefinisikan array sebagai
char arrayName[some_nonconstant_variable]
), jika Anda tidak tahu persis apa yang Anda lakukan, ia hanya bekerja di C99.sumber
Anda harus menggunakan fungsi ANSI untuk membaca baris, mis. uang. Setelah menelepon, Anda perlu bebas () dalam konteks panggilan, misalnya:
sumber
Terapkan metode untuk membaca, dan dapatkan konten dari file (input1.txt)
Semoga bantuan ini. Selamat coding!
sumber
Anda membuat kesalahan dengan mengembalikan pointer ke variabel otomatis. Baris variabel dialokasikan dalam tumpukan dan hanya hidup selama fungsi tersebut hidup. Anda tidak diperbolehkan untuk mengembalikan pointer ke sana, karena segera setelah mengembalikan memori akan diberikan di tempat lain.
Untuk menghindarinya, Anda harus mengembalikan pointer ke memori yang berada di heap eg. lineBuffer dan seharusnya menjadi tanggung jawab pengguna untuk menelepon gratis () ketika ia selesai dengan itu. Sebagai alternatif, Anda dapat meminta pengguna untuk menyampaikan kepada Anda argumen alamat memori tempat Anda menulis isi baris.
sumber
Saya ingin kode dari ground 0 jadi saya melakukan ini untuk membaca isi kata demi kata kamus demi baris.
char temp_str [20]; // Anda dapat mengubah ukuran buffer sesuai dengan kebutuhan Anda dan panjang satu baris dalam File.
Catatan Saya sudah menginisialisasi penyangga Dengan karakter Null setiap kali saya membaca baris. Fungsi ini dapat diotomatisasi, tetapi karena saya membutuhkan bukti konsep dan ingin merancang program Byte By Byte
sumber
int main() {
code
char temp_str [20] = {'\ 0'};code
c akan secara otomatis mengisi setiap slot dengan terminator nol karena cara deklarasi array berfungsi adalah jika array diinisialisasi dengan lebih sedikit elemen yang terdapat pada array, elemen terakhir akan mengisi elemen yang tersisa.char temp_str[20] = {0}
juga mengisi seluruh array karakter dengan terminator nol.Alat saya dari awal:
sumber
fgets
yang dapat digunakan.Menyediakan fungsi portabel dan generik
getdelim
, uji lulus melalui msvc, clang, gcc.sumber
fgets
ada?getdelim
memungkinkan untuk pembatas yang disesuaikan. Juga saya perhatikan tidak memiliki batas panjang garis - dalam hal ini Anda dapat menggunakan stack dengangetline
. (Keduanya diuraikan di sini: man7.org/linux/man-pages/man3/getline.3.html )getdelim
dangetline
telah distandarisasi dalam POSIX.1-2008, orang lain menyebutkan pada halaman ini).fgets
juga standar c, dan bukan spesifik linux