将char数组的数组传递给函数

时间:2014-05-27 20:44:34

标签: c++ arrays function pointers char

在我的程序中,我可能需要加载一个大文件,但并非总是如此。所以我定义了:

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部分是对的,但我不知道它应该是什么。

有人可以帮助我吗?提前谢谢!

4 个答案:

答案 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());

A Side Note:Arrays v / s Vectors

数组是原始C ++数据类型,而Vectors是类,是标准模板库的一部分。这意味着理论上矢量比数组慢。但在实践中,速度下降可以忽略不计。向量提供了两个巨大的好处,成本可以忽略不计

  • 内存管理。您不必删除内存,一旦矢量对象超出范围,分配的内存将被删除。在你的例子中,你似乎不一定需要它,因为在琐碎的情况下你的数组永远不会被销毁
  • 灵活性。对于数组,您必须预先知道预期的大小。矢量根据需要扩展。你不一定需要它,因为你说的矢量大小是固定的。

与矢量相关的成本有两个

  • 性能:向量可能比在数组上运行稍慢,但由于大多数(如果不是全部)操作都被描述为内联函数,编译器会优化其中的内容,并使其或多或少成为作为数组有效。对于固定大小的矢量尤其如此。
  • 内存:Vector是一个在内部使用数组的容器,这意味着Vector对象会有轻微的内存开销。但是将其与您可能正在进行的节省进行比较,但不是分配大量数组,而是逐渐扩展向量。只有在创建大量小向量时,向量的内存开销才是一个问题。在您的情况下,这种开销是微不足道的。

参考文献:

  1. array vs vector vs list
  2. C++ STL vector vs array in the real world
  3. http://www.cplusplus.com/forum/beginner/6321/
  4. http://www.cprogramming.com/tutorial/stl/vector.html

答案 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>?您可能认为它对于正常的字符串向量来说太大而且因此必须使用指针是完全错误的。