堆栈数组C ++的Strcpy行为

时间:2019-12-16 17:06:52

标签: c++ arrays stack heap strcpy

这是我的程序:

#include <cstring>
const int SIZE =10; 

int main() 
{ 
    char aName [SIZE]; // creates an array on the stack
    std::strcpy(aName, "Mary");
    return 0;
}

该程序显然没有用,我只是想了解strcpy函数的行为。

这是签名: char * strcpy ( char * destination, const char * source )

所以当我这样做时: std::strcpy(aName, "Mary");

我正在按值传递变量aName。我知道aName(在主目录中)包含数组的地址。 那么这个断言是正确的吗:strcpy创建一个名为destination的局部变量,该变量的值是我在主函数中的堆栈上创建的数组aName的地址?

我问这个是因为这让我很困惑。每当我遇到地址时,通常是指向 ...

上分配的内存

谢谢!

6 个答案:

答案 0 :(得分:1)

无论何时遇到地址,并不意味着它总是指向分配给堆的内存。

您可以将变量的地址分配给这样的指针

int a=5;
int *myPtr= &a;

现在,myPtr是整数类型的指针,它指向在 stack 上创建的变量的内存,该变量的a值为5。

因此,每当您创建指针并使用new关键字分配内存(的地址)时,它将在 heap 上分配内存。因此,如果我这样分配值,它将在堆栈上

int *myPtr= new int[5];

答案 1 :(得分:1)

  

这个断言是否正确:strcpy创建一个名为destination的局部变量,该变量的值是我在主函数中的堆栈上创建的数组aName的地址?

是的

  

每当我遇到地址时,通常是指向堆上分配的内存...

通常,是的。但并非总是如此。

在C ++中,非动态分配的事物的指针很少见,尽管在C语言中更常见,因为这是拥有“输​​出参数”的唯一方法(C没有引用)。

strcpy是C的标准库中的函数。

答案 2 :(得分:0)

函数参数是它的局部变量。

在此次通话中

std::strcpy(aName, "Mary");

这两个数组(一个是在main中创建的,具有自动存储持续时间,另一个是具有静态存储持续时间的字符串文字)被隐式转换为指向其第一个元素的指针。

因此,您可以通过以下方式想象此调用和函数定义

std::strcpy(aName, "Mary");

 // …

char * strcpy ( /* char * destination, const char * source */ )
{
    char *destination = aName;
    const char *source = "Mary";

    // …

    return destination;
}

甚至喜欢

char *p_to_aName = &aName[0];
const char *p_to_literal = &"Mary"[0];
std::strcpy( p_to_aName, p_to_literal );

 // …

char * strcpy ( /* char * destination, const char * source */ )
{
    char *destination = p_to_aName;
    const char *source = p_to_literal;

    // …

    return destination;
}

在函数内,其参数是具有自动存储持续时间的指针类型的局部变量,该指针类型由指向传递的字符数组的第一个字符的指针初始化

答案 3 :(得分:0)

也许可以看看strcpy()的示例实现:

char* strcpy(char* d, const char* s)
{
    char* tmp = d;

    while (*tmp++ = *s++)
        ;

    return d;
}

这就是全部。将字符从源复制到目标,直到源字符为null(包括null)为止。将指针返回到目的地的开头。完成。

指针指向内存。内存是“堆栈”,“堆”还是“静态”都没关系。

答案 4 :(得分:0)

  

这个断言是否正确:strcpy创建一个名为destination的局部变量,该变量的值是我在主函数中的堆栈上创建的数组aName的地址?

是的。那是对的。虽然我可能不会将其称为局部变量。它是一个参数。局部变量通常表示如下内容:

int localVariable;

“参数”一词通常与以下内容相关:

int myFunction(int parameter) {
    // use parameter some where...
}

但是要点大致相同:它创建了一个变量,一旦函数退出,该变量将超出范围。

  

我问这个是因为这让我很困惑。每当我遇到地址时,通常是指向堆上分配的内存...

是的,这是他们最常用的用例。但这不是他们唯一的用途。指针是地址,每个变量在内存中都有一个地址,无论它是分配在“堆”还是“堆栈”上。

此处使用此命令可能是因为指向char的指针通常用于存储字符串,尤其是在较旧的编译器上。加上arrays "decay" into pointers,可能更容易使用指针这一事实。当然,这样做也向后兼容。

该函数可以像这样简单地使用数组:

char * strcpy ( char destination[], const char source[ )

但是我将假定在这里使用指针更容易(注意:,我认为您不能用C ++返回数组,因此我仍在使用{{ 1}}。但是,即使可以,我仍然认为使用指针仍然更容易,所以我认为在这里并没有太大区别。


指针的另一种常见用法是使用它们作为“按引用传递”的一种方式:

char *

但是,在现代C ++中,实际上首选通过引用传递:

void foo(int * myX) {
    *myX = 4;
}

int main() {
    int x = 0;

    foo(&x);

    std::cout << x; // prints "4"

    return 0;
}

但是我将其作为另一个示例来帮助您理解这一点:在堆上分配的内存并不是唯一使用指针的指针,只是最常用的指针(尽管在现代C ++中实际上动态分配的内存已被大部分替换) std::vector之类的东西,但这不在这里。)

答案 5 :(得分:0)

  

我知道aName(在主目录中)包含数组的地址。

您知道错了。 aName是一个数组。它包含元素,而不是地址。

但是,当您使用数组名称作为值时(例如,将其传递给strcpy时),它将隐式转换为指向数组第一个元素的指针(指针的值是指向对象的内存地址)。这种隐式转换称为衰变

  

这个断言是否正确:strcpy创建一个名为destination的局部变量,该变量的值是我在主函数中的堆栈上创建的数组aName的地址?

这是足够正确的。需要说明的是:它是一个函数参数,而不是局部变量。但是区别在这里并不重要。从技术上讲,调用方负责将参数推入堆栈或将其存储到寄存器中,因此可以认为main是“创建”变量。

  

每当我遇到地址时,通常是指向堆上分配的内存

指针并非与“堆”唯一关联。几乎可以指向任何对象,无论它是动态,静态还是自动存储,甚至是子对象。