while (!fin.eof())
Is one of the common sins of C++。它不會做你想做的事。簡單化是你不知道你是否已經達到了文件的結尾,除非你試圖讀過它。這意味着如果您沒有測試成功讀取的結果,您會得到額外的讀取失敗和未定義的結果。
測試成功的閱讀非常簡單,幾乎涵蓋了您可能在學校任務中遇到的各種失敗案例,包括EOF。
while (fin >> buffer)
{
// do stuff
}
這意味着大部分的讀邏輯的壓縮下來:
if (!fin)
{
cout << "can't read the file!!" << endl;
return -1;
}
while (fin >> buffer)
{
// do stuff
}
我們走了什麼分配要求之前,正確的方法做你想要做的事情是
int tempnumber;
std::vector<int> numbers;
while (fin >> tempnumber) // read directly into a number. No further parsing needed.
{
numbers.push_back(tempnumber);
}
if (fin.eof()) // now is when you check eof.
// If we didn't get to the end of the file,
// there is something wrong with the file
{
std::cout << "Before sort:" << std::endl;
for (int number: numbers)
{
std::cout << " " << number << std::endl;
}
// And because I know why you are doing this, you finish off with:
std::sort(numbers.begin(), numbers.end());
std::cout << "After sort:" << std::endl;
for (int number: numbers)
{
std::cout << " " << number << std::endl;
}
}
else // stopped somewhere other than the end of the file. Bad file
{
std::cerr << "improperly formatted file" << std::endl;
return 0;
}
可悲的OP有一位教官認爲,學習射擊步槍你應該先學會製造步槍,所以OP無法利用C++的高級特性。我更多的是一門教學邏輯,然後教授低級語言基礎類的人,所以我當然認爲這種教學風格是次優的。
還要注意顯式命名空間的使用。在我看來,這超過了輸入一些額外字符的難度。
但如何做到這一點與動態大小的數組沒有高層次的構造? OP讀取文件兩次:一次大小,第二次獲取內容。相比於你在計算機上做的任何其他操作,文件IO速度都很慢,但工作起來很慢。爲了不讀兩次,一個簡單的單鏈表可以工作,但是OP已經聲明(in their previous question)他們最終需要一個數組來排序列表。
沒有那未盡的要求,該解決方案解決了下來不要使用數組,不轉換爲數字,並
while (fin >> buffer)
{
cout << buffer<< endl;
}
完成。還有其他有趣的技巧,將fin
直接轉換成cout
,但實質上,它是這樣做的。
這可以通過定義一個動態數組負擔很重的類來解決,但爲什麼? std :: vector填補了市場的空白,爲什麼搶OP的指導者可能是下一個任務?
所以讓我們通過手動調整數組大小來實現。我們要做的是蠻力和白癡。每當數組即將溢出時,我們將創建一個新數組,它是舊數組的兩倍,將舊數據複製到新數組中,釋放舊數據並指向新數組。
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
using namespace std;
int main(int argc, char* argv[])
{
if (argc > 1)
{
char buffer[100]; // no need for pointer. allocate a big buffer that is
// unlikely to overflow
int * numbers = new int[10]; // make a dynamic array. 10 seems like a
// good starting size
int *
被稱爲原始指針。它不受保護。它必須手動管理。如果出現任何問題,它往往會丟失,它指向的內容變得無法恢復。不要在真實世界中使用原始指針,如果沒有真正的理由,你可以誠實地向其他人解釋和解釋。如果其中一個人說:「但是你可以這樣做。」而且他們是對的,那就做吧。
在考慮使用std::unique_ptr
和[std::shared_ptr][5]
按照該順序的原始指針檢查之前。 There are a whole raft of better ways to do this,但賠率是指導者將拒絕允許他們。知道它們存在並在可能時使用它們。他們會爲你節省很多的痛苦。
size_t capacity = 10; // number of items that can go into numbers
當做索引變量時,贊成size_t
。它是無符號的(沒有值< 0)並且保證能夠存儲可以構造的最大對象的字節大小。換句話說,如果它不夠大,你的程序就無法工作。
size_t size = 0; // number of items currently in numbers
ifstream fin(argv[1]); //open the file
while (fin >> buffer) // will read up to next whitespace in file.
這可以讀取超過緩衝區的末尾。被警告。這就是爲什麼我們把緩衝區做得很大
{
int temp = atoi(buffer);
atoi
是原油和容易出現故障的從我這裏不是排渣ÇC的石器時代遺留下來的。一個理智的C程序員使用它時要注意同樣的事情,因爲它是一個非常古老而且非常愚蠢的函數。只能在抗議或極度受控的情況下使用它。
首選strtol
及其家族轉換字符數組和std::stoi
和家庭轉換std::string
s,因爲他們可以爲您捕捉錯誤。優先將std::string
用於char數組。
if (capacity == size) // need to resize numbers
{ // make a bigger array, copy into bigger array, replace smaller array
int * temp = new int[capacity * 2]; // make a bigger array
memcpy(temp, numbers, capacity * sizeof(numbers[0]));
像atoi
,memcpy
是原油,但工程。如果向量不在這個賦值中,std :: copy也可能出來。 memcpy
適用於簡單的值,如int和double,但贊成std::copy
結構和類。memcpy
無意識地複製對象或結構中的內容,他們經常在幕後發生其他事情,如指針,複製時需要特殊處理。
delete numbers; // free the array currently used by numbers
numbers = temp; // point at new, bigger array
capacity *= 2; // update the capacity to the new size
}
numbers[size++] = temp;
}
std::cout << "Before sort:" << std::endl;
for (size_t index = 0; index < size; index++)
{
std::cout << " " << numbers[index] << std::endl;
}
fin.close();
// call to sorting function goes here.
}
return 0;
}
而且在一個切面正pastable塊:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
using namespace std;
int main(int argc, char* argv[])
{
if (argc > 1)
{
char buffer[100]; // no need for pointer. allocate a big buffer that is
// unlikely to overflow
int * numbers = new int[10]; // make a dynamic array. 10 seems like a
// good starting size
size_t capacity = 10; // number of items that can go into numbers
size_t size = 0; // number of items currently in numbers
ifstream fin(argv[1]); //open the file
while (fin >> buffer) // will read up to next whitespace in file.
{
int temp = atoi(buffer);
if (capacity == size) // need to resize numbers
{ // make a bigger array, copy into bigger array, replace smaller array
int * temp = new int[capacity * 2]; // make a bigger array
memcpy(temp, numbers, capacity * sizeof(numbers[0]));
delete numbers; // free the array currently used by numbers
numbers = temp; // point at new, bigger array
capacity *= 2; // update the capacity to the new size
}
numbers[size++] = temp;
}
std::cout << "Before sort:" << std::endl;
for (size_t index = 0; index < size; index++)
{
std::cout << " " << numbers[index] << std::endl;
}
fin.close();
// call to sorting function goes here.
}
return 0;
}
現在,我們有邏輯下,有改進整體轉換。首先是將main
中的所有代碼以及它自己的read
功能。這種方式主要是很好,很乾淨,有兩個定義好的子任務,每個子任務都有自己的功能:read
和sort
。
爲什麼?人類的頭腦比小的更容易理解小東西。如果一次只有一個問題,那麼保持人類關注也更容易。功能比一個大的read
和sort
功能短。 read
和sort
意味着兩件事情正在進行。當read
干擾sort
的運作時,大樂趣來自於此。你在調試哪個?兩個都。除非共同混合具有顯着的,可測量的和完全必要的收益,否則將分開的工作分開。
如果您將所有內容都轉換爲main
,you get one massive, confused mess。閱讀代碼變得更加困難。這意味着調試變得更加困難。做任務需要更長的時間。在更直接的方面,標記變得更難。等級變低。
在作爲程序員的現實生活中,由於同事的嘲笑,代碼評審失敗以及最終被從工作中釋放出來,因爲您的個人生產力吸收和清理代碼會拖累整個部門的績效。
您有內存泄漏。你分配一個新的'buffer'數組,但可以在'delete'之前'返回'。 –
@JoelCornett好吧,我只是把緩衝區和分配在while循環一起 – 7llllll
@JoelCornett那麼現在呢? – 7llllll