通过引用传递字符数组

18

我正在通过引用传递字符数组,但当我从函数返回并打印该数组时,什么也没有显示。我做错了什么?

#include <iostream>

using namespace std;

void func(char []);
int main()
{
   char a[100];
   func(a);

   cout << a<<endl;
   return 0;
}

void func(char *array)
{
   array="Inserting data in array a";
   cout << array<<endl;
}

致敬


1
你把数据插入数组的哪里?能展示一下那段代码吗? - juanchopanza
你为什么要创建一个包含100个字符的数组,却只存储一个字符...你想要存储多个字符吗? - Anirudha
在阅读答案之前,请确保您了解以下几点:1. 'a' 是一个地址,您正在将其复制到 'array' 中。到目前为止一切都很好。2. "Inserting data in array" 这个字符串产生一个地址。在 func() 函数中,您正在使用此地址覆盖 'array'。 - tez
@tez: 不,'a' 不是一个地址。 'a' 是一个有100个字符的数组。在许多情况下,它可以被隐式转换为指针。但它本身不是一个指针。 - Benjamin Lindley
1
@tez:不,这种情况下'a'仍然是一个字符数组,确切地说是12个字符(空终止符是隐含的)。实际上,像“hello world”这样的字符串字面量也是一个char数组。但它是一个存在于只读内存中的数组。所以你不能修改它。当你这样做时:char a[] = "hello world";-- 存在于只读内存中的“hello world”数组被复制到本地char数组'a'中。因此,一个字符串字面量并不总是生成一个指针。它和数组一样,在同样的地方生成指针,因为它是一个数组。 - Benjamin Lindley
显示剩余3条评论
9个回答

12

你可以尝试做的是:

void func( char (& array)[10] ) {

}

根据螺旋法则,这被翻译为:一个对长度为10([10])的字符数组(char)的引用(&)。


8

你没有通过引用传递数组(也不应该这样做,在这里对你没有好处)。你正在传递指向其第一个元素的指针。然后在函数内部重新分配该指针以指向其他内容。这对数组没有影响。如果你想更改数组的内容,则需要将数据复制到指针指向的位置。你可以使用strcpy或类似函数:

strcpy(array, "Inserting data in array a");

作为一个侧面的评论,但非常重要。在C++中,我们不再需要处理这样的事情。这是在C中处理事情的方式。以下是我们在C++中处理事情的方式:

#include <string>
#include <iostream>

void func(std::string & str)
{
    str = "Inserting data into the string";
    std::cout << str << std::endl;
}

int main()
{
    std::string a;
    func(a);
    std::cout << a << std::endl;
}

1
如何通过引用传递数组? - Naruto
1
@UmerFarooq:你可以将函数签名更改为func(char (&array)[100]),但在这种情况下没有用。你不能对数组进行赋值,你仍然需要使用类似strcpy的东西进行复制。 - Benjamin Lindley
我想我不需要像你展示的那样做引用。我正在通过引用传递数组,因为当我从用户那里获取输入时,数组的内容会发生变化。 - Naruto
你能告诉我为什么我的在函数内部改变数组数据的方法不起作用吗? - Naruto
@UmerFarooq:我的回答中前四个句子就是在解释这个问题。 - Benjamin Lindley
显示剩余2条评论

8
您可以通过引用传递指针。为此,您需要使用以下语法:
void func(char *&array)
{
    // ....
}

函数内部使用该参数作为常规指针。如果修改此指针所指向的值,则这些更改将在外部可见。

你可以这样做,但是试图将数组传递给函数是没有用的。 - Benjamin Lindley
2
这种方式main传递a的值给函数是行不通的:代码将无法编译,出现消息“无法从类型为‘char’的临时变量初始化非const引用类型‘char&’”。 - Sergey Kalinichenko
@dasblinkenlight,你是对的。请把我的注释视为独立的内容。 - Kirill Kobelev

4

我使用了上面的答案,但我需要进行扩展,以便像这样打印出数组的实际大小:

template<size_t n> void foo(char (&array)[n])
{
    // ...
    std::cout << "array size: " << n << std::endl;
    // ...
}

2
尝试以下方法:
void function(char* MyArray)
{
    MyArray = "Hello World";
    std::cout << "Address of MyArray inside function: " << (void*)MyArray << std::endl;
}

int main()
{
    char MyArray[10];
    std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;
    function(MyArray);
    std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;

    std::cin.get();
    return 0;
}

通过这个例子,你将会发现在函数内部,指向数组的指针只是一个副本。当你赋值“Hello World”时,你只是改变了副本的地址,而不是主函数中数组的地址。

这个例子实际上可以工作,因为这样你就不需要在函数内部复制指针:

void function(char** MyArray)
{
    *MyArray = "Hello World";
    std::cout << "Address of MyArray inside function: " << (void*)*MyArray << std::endl;
}

int main()
{
    char* MyArray = 0;
    std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;
    function(&MyArray);
    std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;

    std::cin.get();
    return 0;
}

但这仍然是不好的风格。在使用字符数组时,你应该像这样做:
void function(char* MyArray)
{
    strcpy(MyArray, "Hello World");
    std::cout << "Address of MyArray inside function: " << (void*)MyArray << std::endl;
}

int main()
{
    char* MyArray = 0;
    MyArray = new char[15];

    std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;
    function(MyArray);
    std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;

    delete [] MyArray;

    std::cin.get();
    return 0;
 } 

但是正如其他人提到的,我建议使用std::string并通过引用传递它,而不是使用字符数组。因为与std::string相比,字符数组是不安全的。像这样:

void function(std::string& MyString)
{
    MyString = "Hello World";
}

int main()
{
    std::string MyString;
    function(MyString);

    std::cin.get();
    return 0;
}

如果我用char MyString[50]代替std::string MyString;,并通过强制转换(std::string)(MyString)将其传递给函数,这样做可以吗?如果不行,有什么缺点? - BreakBadSP

0

我知道这篇文章有点老,但我最近发现一种将char数组作为引用传递并在您的示例中实现它的方法..

我不知道为什么在作为参考传递char数组时要使用[0]作为数组索引,但是这段代码可以工作。

我花了很多时间在网上寻找如何做到这一点,希望对某些人有所帮助。

#include <iostream>

using namespace std; 

void  func(char arr[3]);

int main()
{
  char a[3];
  a[0] ='a'; 
  a[1] ='b';
  a[2] ='c';

 //passing the char array as a refrence
 func(&a[0]);

 cout<< "checking the values outside of the func"<<endl;
 cout << a<<endl;
 return 0;
}

void func(char arr[3])
{
   cout<<"Inserting data in array a in the function " <<endl;
   cout << &arr[0]<<endl;
}

将对象作为引用传递的主要思想是不创建对象的副本,因为这可能会使用内存资源。因此,在 char 数组的情况下,您可能有非常大的数组,因此将整个 char 数组对象作为参数发送是低效的。这就是为什么我们应该改为通过引用传递的原因。

0

你正在传递一个指向数组的指针(func (char* array)),然后在函数内部你正在改变指针的值以指向静态字符串。

你需要通过 strcpy() 将新数据复制到数组中,或者通过引用传递数组的指针:

void func(char*& array); // reference to pointer

或者:

strcpy(array, "data");

更好的做法是使用std::vector<>std::string

0

对本地数组的引用是C++中非常强大的武器之一。再加上模板。这里有一个也许不太平凡但仍然简单的例子。

// set all element of a given native array reference 
// to the same value
// return the reference to the same array
    template<typename T, size_t N, typename array_type = T[N] >
    inline
        array_type&  /* return reference to T[N] */
        all_val 
         (  T(&arf)[N],  /* arg reference to T[N] */
            T val   )
    {
        // range for() works on native arrays
        // begin(arf) / end(arf)
        // work as expected
        for (auto & elem : arf) {
            elem = val ;
        }
        // array can not be returned by value
        // but this is allowed in standard C++
        // return type is native array reference
        return arf;
    }

当使用上述方法时,应该考虑并保留返回类型作为本地数组引用。
        using charray_type = char[0xF];
        charray_type charray;
        // decaying to pointer to T*
        // you do not want this
        auto pointer_to_char = all_val(charray, '*');
        // you do want this
        // preserving the ref to array
        charray_type& charray_ref = all_val(charray, '*');
        // normal native arr usage
        charray_ref[0] = '*';
        assert(charray[0] == charray_ref[0]);

我认为这相当简单,并且独特于标准C++。


-1

第一行出现错误,iostream.h ... 其次,您没有向数组中插入任何元素...并且在函数中传递了一个a,您必须将数组的地址传递到该函数中,但在此之前,请重写代码以在数组中添加一些内容。


不要使用1998年之前的书籍。正确的头文件是<iostream> - Benjamin Lindley
@BenjaminLindley 但是根据新的编译器,这是一个错误...无论如何,谢谢,我会去找一下的... - agaonsindhe
1
什么编译器?应该相反。现代编译器通常会将iostream.h标记为已弃用或直接错误,就像这里的情况:http://ideone.com/m0TwXl - Benjamin Lindley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接