在我的程序中,我可能需要加载一个大文件,但并非总是如此。所以我定义了:
char** largefilecontents;
string fileName="large.txt";
当我需要加载文件时,程序会调用此函数:
bool isitok=LoadLargeFile(fileName,largefilecontents);
功能是:
bool LoadLargeFile(string &filename, char ** &lines)
{
if (lines) delete [] lines;
ifstream largeFile;
#ifdef LINUX
largeFile.open(filename.c_str());
#endif
#ifdef WINDOWS
largeFile.open(filename.c_str(),ios::binary);
#endif
if (!largeFile.is_open()) return false;
lines=new char *[10000];
if (!lines) return false;
largeFile.clear();
largeFile.seekg(ios::beg);
for (int i=0; i>-1; i++)
{
string line="";
getline(largeFile,line);
if (largeFile.tellg()==-1) break; //when end of file is reached, tellg returns -1
lines[i]=new char[line.length()];
lines[i]=const_cast<char*>(line.c_str());
cout << lines[i] << endl; //debug output
}
return true;
}
当我查看此功能的调试输出时,&#34; cout&lt;&lt; line [i]&lt;&lt; endl;&#34;,没关系。但是当我在主程序中检查这个时,这一切都搞砸了:
for (i=0; i<10000; i++)
cout << largefilecontents[i] << endl;
因此在函数LoadLargeFile()
中,结果很好,但没有LoadLargeFile()
,结果都搞砸了。我的猜测是函数的char ** &lines
部分是对的,但我不知道它应该是什么。
有人可以帮助我吗?提前谢谢!
答案 0 :(得分:1)
检查通过值传递的内容以及通过引用传递的内容。问题是在函数终止后不会保留更改。
但是,我觉得问题从声明2D char数组的方式开始。我认为你是静态地做的,如果你能够动态地做到这一点,就像这样:
// We return the pointer
char **get(int N, int M) /* Allocate the array */
{
/* Normally, you should check if allocation was ok. */
char** ary = new char*[N];
for(int i = 0; i < N; ++i)
ary[i] = new char[M];
return ary;
}
void delete2Darray(char** p, int N) {
int i;
for(i = 0 ; i < N ; i++)
delete [] p[i];
delete p;
}
void foo(char** p)
{
printf("%s\n", p[0]);
strcpy(p[0], "sam");
printf("%s\n", p[0]);
}
int main()
{
char** A = get(1, 5);
strcpy(A[0], "dad");
foo(A);
printf("%s\n", A[0]);
delete2Darray(A, 1);
return 0;
}
给出输出:
dad
sam
sam
这是C中的简单example。 (这是我的伪网站)。
答案 1 :(得分:1)
问题在于您使用line.c_str
的位置。您首先使用lines[i]=new char[line.length()];
为新字符串分配内存,但随后使用指向局部变量line[i]
中的c_str的指针覆盖line
中的指针。当c_str
超出范围时,此line
将被销毁。您需要做的是使用strcpy
而不是简单的指针赋值。
尝试以下
lines[i]=new char[line.length()+1]; //Thanks @Claptrap for the catch
strncpy(lines[i], line.c_str(), line.length()+1); //Note, strcpy is not considered safe.
//Use strncpy
如果您想严格遵守c ++方式,那么我建议使用@ christian-hackl的建议
std::vector<std::string> largefilecontents; //Since in your case 10000 is fixed
...
bool LoadLargeFile(string &filename, std::vector<std::string> &lines)
{
...
//lines=new char *[10000];
//if (!lines) return false;
lines.resize(10000); //Since in your case 10000 is fixed
...
for...
if(i >= lines.size()) break; //safety net in case more than 10000 lines
lines[i]="";
getline(largeFile,lines[i]);
if (largeFile.tellg()==-1) break; //when end of file is reached, tellg returns -1
//lines[i]=new char[line.length()];
//lines[i]=const_cast<char*>(line.c_str());
数组是原始C ++数据类型,而Vectors是类,是标准模板库的一部分。这意味着理论上矢量比数组慢。但在实践中,速度下降可以忽略不计。向量提供了两个巨大的好处,成本可以忽略不计
与矢量相关的成本有两个
参考文献:
答案 2 :(得分:1)
行
lines[i]=new char[line.length()];
lines[i]=const_cast<char*>(line.c_str());
不要按照你的期望去做
lines[i] = new char [line.length()]
为字符串分配一些字节,但不包括字符串的结尾\ 0。
lines[i]=const_cast<char*>(line.c_str());
将其设置为指向一个本地字符串变量,该变量持续一次迭代。你需要做的是像在指针上一样在堆上分配缓冲区,然后复制到它
lines[i] = new char[line.length() + 1];
strcpy(lines[i], line.c_str() );
如果这是来自学校的练习,那么我不会说更多,但如果它是一个真正的程序,那么你应该使用vector<string>
来保持简单而不是摆弄原始数组。
另一件事是,如果在读取行之前将所有指针初始化为NULL会更好,以便函数的调用者知道何时停止处理指针。
你可以这样编写
for (int j = 0; lines[j] != NULL; ++j)
cout << lines[j] << endl;
答案 3 :(得分:0)
这段代码有许多不足之处,因此很难对其进行推理。例如:
if (!lines) return false;
没用,因为new
(在任何正常环境中)都不返回null但是如果内存耗尽则抛出异常。
接下来的事情是,为什么魔数10000?如果您的文件包含超过10000行,会发生什么?看看你的循环:
for (int i=0; i>-1; i++)
它只增加i
,直到它具有int
的最大允许值,此时增量会产生未定义的行为(例如看似随机的崩溃)。
接下来,这一行:
getline(largeFile,line);
操作后不检查流是否有错误,只是假设读数有效。这不是一个好习惯。
最后,这一行:
lines[i]=const_cast<char*>(line.c_str());
抛弃char const *
的成本也会产生未定义的行为。
你甚至尝试只是存储&#34;大文件的内容&#34;在std::vector<std::string>
?您可能认为它对于正常的字符串向量来说太大而且因此必须使用指针是完全错误的。