【问题标题】:Trying to avoid segmentation fault, but my output looks weird (C++)试图避免分段错误,但我的输出看起来很奇怪(C++)
【发布时间】:2011-05-05 05:13:03
【问题描述】:

我正在处理的一个家庭作业项目使用静态和动态数组。但是,我还没有实现动态数组,这是一个奇怪的差异,试图获取我的静态数组的长度。

我使用了一系列 cout 语句来尝试找出导致我出现分段错误的原因,因为这个过程看起来很简单。我发现在我的驱动程序中,它正在计算正确的范围和长度,但是一旦我将数组传递给用户定义的类函数,在同一个数组上执行的相同语句会产生不同的结果。

我的驱动函数:

using namespace std;

#include <iostream>
#include "/user/cse232/Projects/project07.string.h"

int main()
{
  const char string1[] = {'a', 'b', 'c', 'd', 'e', 'f'};
  String test1();
  cout << "Size of array: " << sizeof(string1) << endl;
  cout << "Size of item in array: " << sizeof(char) << endl;
  cout << "Length of array: " << (sizeof(string1)/sizeof(char)) << endl;
  cout << "Range of array" << (sizeof(string1)/sizeof(char))-1 << endl << endl;

  String test2(string1);
}

运行时,我从驱动程序获得以下输出:

Size of array: 6
Size of item in array: 1
Length of array: 6
Range of array5

我的支持文件:

/* Implementation file for type "String" */

using namespace std;

#include <iostream>
#include "/user/cse232/Projects/project07.string.h"

String::String( const char Input[] )
{

  cout << "Size of array: " << sizeof(Input) << endl;
  cout << "Size of item in array: " << sizeof(char) << endl;
  cout << "Length of array: " << (sizeof(Input)/sizeof(char)) << endl;
  cout << "Range of array" << (sizeof(Input)/sizeof(char))-1 << endl << endl;

/*  Bunch of reallocation stuff that is commented out 
for the time being, unimportant*/
}

String::~String()
{
  Capacity = 0;
  Length = 0;
  Mem = NULL;
}

这是我从支持文件中得到的输出,

Size of array: 4
Size of item in array: 1
Length of array: 4
Range of array3

这显然是不对的。如果有帮助,这里是头文件(省略未实现的函数)。它是不可改变的:

/******************************************************************************
   Project #7 -- Interface file for type "String"
******************************************************************************/

#ifndef STRING_
#define STRING_

using namespace std;

#include <iostream>

class String
{
  private:

    unsigned Capacity;  // Number of memory locations reserved
    unsigned Length;    // Number of memory locations in use
    char * Mem;         // Pointer to memory to hold characters

  public:

    // Construct empty string
    //
    String()
    {
      Capacity = 0;
      Length = 0;
      Mem = NULL;
    }

    // Destroy string
    //
    ~String();

    // Construct string by copying existing string
    //
    String( const String& );

    // Construct string by copying C-style character string
    //
    String( const char[] );

#endif

我最大的问题是为什么我得到两个单独的输出。第一个是我在分配内存时需要使用的;否则我会遇到分段错误。谁能给点建议?

【问题讨论】:

  • 我测试过的另一件事是在我的支持文件中的 Input[0]、Input[1] 等处打印输入。它识别了 Input[5] = 'f' 但它计算的长度和范围与我的驱动程序文件中的数组不同,即使数组相等。
  • 请注意,String test1() 确实创建String 对象。相反,它 forward 声明了一个返回 String 并且不接受任何参数的函数。你的意思可能是String test1;

标签: c++ arrays segmentation-fault


【解决方案1】:

您的函数实际上正在做一些您没有意识到的事情 - 它会将您传递的数组衰减为指向第一个元素的指针。

基本上你的函数签名:String::String( const char Input[] ) 将等同于签名String::String(const char *input)

因此,当您执行sizeof 时,您实际上得到的是char * 的大小,而不是数组的大小。

您不能将数组直接传递给函数并期望能够获得数组的大小。如果你必须使用这样的原始数组,你可以改变你的函数,以便你传递数组的大小。如果您不能修改签名,那么您可以做的另一件事是放入一个标记值(如\0 字节)并使用循环来计算数组的大小。

编辑

我认为你真正想了解的是C-style strings,而不是仅仅使用非空终止的字符数组。这确实符合您的任务似乎希望您执行的模型,并且允许您避免操纵这些不可变的标头。

【讨论】:

  • 您搜索的词是“decay”。
  • 有没有办法可以将整个数组传递给函数,而不仅仅是指向第一个元素的指针?
  • @user212562:使用std::vector
  • @user212562 - 考虑到您的头文件是不可变的,我认为我的编辑可能是您的作业希望您采用的路径(使用 C 样式字符串)。
  • @user212562:如果您尝试按值传递数组,它将衰减为指向第一个元素的指针。如果您通过引用传递数组,则不会衰减,但这有其他含义(数组的大小是类型的一部分,如果您通过引用传递数组,则必须是固定的——函数只接受给定大小的数组——或者你可以将函数设为模板并让编译器推断出大小——可能超出你的作业范围。在任何一种情况下,另一个缺点是它动态分配数组就没那么简单了。
【解决方案2】:

其他人已经回答了你的问题,所以我只是用一个小想法来补充它 - 一种方法可以将数组传递给函数,而不会使其衰减为指针。

const size_t SIZE = 6; //Or whatever other array size you want to pass. 
String::String(const char (&Input)[SIZE])
{
    //TODO
}

由于总是计算数组的大小并不容易,因此更好的机制如下所示 -

template<size_t N>
String::String(const char (&Input)[N])
{
    //TODO
}

如果你不知道size_t 是什么意思,就假设它现在类似于int,你最终会了解更多关于这方面的知识(或者通过自学,或者在一些教科书中。可能是前任的)。

这个函数看起来有点奇怪的参数 -

const char (&Input)[SIZE]

表示你正在通过

  • 引用(用 & 表示)
  • Input
  • 它是对由 const char 组成的数组的引用(注意:如果我将&amp; 放在括号外,如下所示: const char &amp; Input[SIZE],那么它将被视为@987654330 的数组@'s - 因此需要引入括号以确保引用是数组本身,而不是数组中的每个元素)
  • 数组的大小是SIZE,其中SIZE 必须是一个常数。

如果您不确定 template 行的全部内容,那可能超出了本次讨论的范围 :-)

所有这些都只适用于真正的数组,其大小是一个可以在编译时计算的常量值。否则,它将无法工作,您将不得不使用标记值(如 '\0' 并通过循环内容动态计算“数组”的长度。

【讨论】:

  • 我只能传递那个大小的数组吗?如果我想在大小为 6 的数组和大小为 3 的数组上使用它怎么办?
  • 是的,第一个版本迫使程序员您计算数组大小并将其放入其中。第二个(模板)版本会为你做这件事,它会在编译时计算数组的大小(它必须在编译时计算才能工作)所以你不必这样做。跨度>
【解决方案3】:

很遗憾,您不能像这样传递数组。当你有这样的功能时:

String::String( const char Input[] )

你只传递了一个指向第一个元素的指针。您还需要将数组的大小传递给构造函数。

【讨论】:

  • 我认为我不能传递两个参数,因为 .h 文件声明了“String(const char[]);”。我无法更改 .h 文件,因此我必须确定一种方法来测量 Input 在传递给函数后的长度。
  • 你要么必须传递两个参数,要么定义一个让你识别最后一个元素的约定。例如,C“字符串”使用 NUL (\0) 字符的约定来标记数组的结尾。
【解决方案4】:

一旦将数组传递给函数,编译器就不再知道它的大小

被调用的函数只是看到

foo(char[])

它不知道它有多大,数组已经变成了一个指针,当你询问指针的大小时,你得到 4(在 32 位机器上)

数组的内存表示不包含其长度。这是一个众所周知且难以解决的问题,这就是 std::vector 存在的原因

【讨论】:

  • 我能否将数组传递给函数,使其能够识别整个数组?
  • 如果你的赋值不允许使用像 std::vector 这样花哨的 c++ 东西,那么你不能,你必须将长度作为第二个参数传递
猜你喜欢
  • 1970-01-01
  • 2018-09-12
  • 1970-01-01
  • 2015-09-18
  • 2018-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
相关资源
最近更新 更多