【问题标题】:How do I return an array of chars?如何返回一个字符数组?
【发布时间】:2020-05-06 11:56:32
【问题描述】:

如果我的函数是void,程序可以正常运行。但是我必须返回值并且有问题。

#include <iostream>
#include <cstring>

using namespace std;

char* fun(char arr[][100]);

int main() {
    char arr[5][100] = { "Saturn", "Venus","Mars", "Earth", "Neptun" };
    char *inscription = fun(arr);
    std::cout << inscription;
}

char* fun(char arr[][100]) {
    char longer[100];
    strcpy_s(longer, arr[0]);
    for (int i = 0; i < 5; ++i) {
        if (strlen(arr[i]) > strlen(longer))
            strcpy_s(longer, arr[i]);
    }
    return longer;
}

我会很感激你的回答。

【问题讨论】:

  • 为什么不使用std::string
  • 因为这是 C++,所以不要让事情变得复杂,只需使用 std::stringstd::vector&lt;std::string&gt;
  • 为什么必须对找到的数据进行硬拷贝?你不能只返回一个指向它的指针吗?
  • 只需将数组放入结构中并返回即可。响应。使用std::array。然后编译器生成字节复制代码,并且您没有过时的指针。
  • 我假设使用 c 字符串而不是正确的 c++ std::string 是分配的要求。

标签: c++ arrays char


【解决方案1】:

如果你想从一个函数返回一个字符数组,我看到两个选项:

  • a) 创建一个堆分配的字符数组并返回一个指向它的指针
  • b) 给函数一个要填充的字符数组

一)

char* fun(char arr[][100]) {
    char* longer = new char[100];
    // ... do something
    return longer
}

b)

int main()
{
    //...
    char longer[100];
    fun(arr, longer);
    //...
}

void fun(char arr[][100], char* longer) {
    // ... fill longer
}

我认为最好的方法是第二种方法,因为您不会在堆上分配任何东西,从而避免处理不必要的问题。您应该尽可能避免堆分配,因为如果调用者不释放内存并花时间去做,它们可能会导致问题。

【讨论】:

  • “我认为最好的方法是第二种”不,最好的方法是在处理字符串时使用std::string并按值返回
  • 使用原始字符数组时的最佳方法
【解决方案2】:

试着把函数改成这样:

char* fun(char arr[][100]) {
    char *longer = new char[100];
    strcpy_s(longer, arr[0]);
    for (int i = 0; i < 5; ++i) {
        if (strlen(arr[i]) > strlen(longer))
            strcpy_s(longer, arr[i]);
    }
    return longer;
}

【讨论】:

    【解决方案3】:

    问题是你创建了一个局部变量,然后返回一个指向它的指针,但是当函数完成时,变量被销毁,所以指针变得无效。您使用无效指针 BOOM 进一步操作。最简单的处理方法——使用类函数。

    /* main.cpp */
    
    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    struct Func
     {
      char longer[100];
    
      explicit Func(char arr[][100])
       {
        strcpy(longer, arr[0]);
    
        for (int i = 1; i < 5; ++i) {
            if (strlen(arr[i]) > strlen(longer))
                strcpy(longer, arr[i]);
        }
       }
    
      const char * result() const { return longer; }
     };
    
    int main() {
        char arr[5][100] = { "Saturn", "Venus","Mars", "Earth", "Neptun" };
    
        Func fun(arr);
    
        cout << fun.result() << endl ;
    
        return 0;
    }
    

    此代码还有一些其他问题,但我将其保留在此处。

    【讨论】:

      【解决方案4】:

      对于初学者,您必须正确定义函数。它应该有第二个参数,用于指定传递数组中元素的数量。

      至少可以这样看

      char * fun( char arr[][100] , size_t n ) 
      {
          char *longer = arr[0];
      
          for ( size_t i = 1; i < n; ++i ) 
          {
              if ( std::strlen(longer) < std::strlen( arr[i] ) )
              {
                  longer = arr[i];
              }
          }
      
          return longer;
      }
      

      这是一个演示程序

      #include <iostream>
      #include <cstring>
      
      const size_t N = 100;
      
      const char * fun( const char arr[][N] , size_t n ) 
      {
          const char *longer = arr[0];
      
          for ( size_t i = 1; i < n; ++i ) 
          {
              if ( std::strlen(longer) < std::strlen( arr[i] ) )
              {
                  longer = arr[i];
              }
          }
      
          return longer;
      }
      
      int main() 
      {
          char arr[][N] = 
          { 
              "Saturn", "Venus","Mars", "Earth", "Neptun" 
          };
      
          const size_t M = sizeof( arr ) / sizeof( *arr );
      
          const char *inscription = fun( arr , M );
      
          std::cout << inscription << '\n';
      
          return 0;
      }
      

      程序输出是

      Saturn
      

      但是该功能有一个缺点。例如,通常用户可以将值0 作为第二个参数传递。在这种情况下,将传递的指针作为第一个参数取消引用可能会导致未定义的行为。而且函数strlen被调用了多次。

      这里有一个更安全的函数实现。

      #include <iostream>
      #include <cstring>
      
      const size_t N = 100;
      
      const char ( * fun( const char arr[][N] , size_t n ) )[N] 
      {
          const char ( *longer )[N] = arr;
          size_t longer_len = 0;
      
          if ( n != 0 )
          {
              longer_len = std::strlen( *longer );
          }
      
          for ( size_t i = 1; i < n; ++i ) 
          {
              size_t len = std::strlen( arr[i] );
      
              if ( longer_len < len )
              {
                  longer = arr + i;
                  longer_len = len;
              }
          }
      
          return longer;
      }
      
      int main() 
      {
          char arr[][N] = 
          { 
              "Saturn", "Venus","Mars", "Earth", "Neptun" 
          };
      
          const size_t M = sizeof( arr ) / sizeof( *arr );
      
          auto inscription = fun( arr , M );
      
          std::cout << *inscription << '\n';
      
          return 0;
      }
      

      它的输出是

      Saturn
      

      如果函数中使用的声明看起来很复杂,那么您可以使用说明符 auto 来简化它们。例如

      auto fun( const char arr[][N] , size_t n ) 
      {
          auto longer = arr;
          size_t longer_len = 0;
      
          if ( n != 0 )
          {
              longer_len = std::strlen( *longer );
          }
      
          for ( size_t i = 1; i < n; ++i ) 
          {
              size_t len = std::strlen( arr[i] );
      
              if ( longer_len < len )
              {
                  longer = arr + i;
                  longer_len = len;
              }
          }
      
          return longer;
      }
      

      此外,如果您希望该函数不依赖于二维数组的大小元素,您可以将该函数声明为模板函数。 给你。

      #include <iostream>
      #include <cstring>
      
      template <size_t N>
      auto fun( const char arr[][N] , size_t n ) 
      {
          auto longer = arr;
          size_t longer_len = 0;
      
          if ( n != 0 )
          {
              longer_len = std::strlen( *longer );
          }
      
          for ( size_t i = 1; i < n; ++i ) 
          {
              size_t len = std::strlen( arr[i] );
      
              if ( longer_len < len )
              {
                  longer = arr + i;
                  longer_len = len;
              }
          }
      
          return longer;
      }
      
      int main() 
      {
          const size_t N = 100;
          char arr[][N] = 
          { 
              "Saturn", "Venus","Mars", "Earth", "Neptun" 
          };
      
          const size_t M = sizeof( arr ) / sizeof( *arr );
      
          auto inscription = fun( arr , M );
      
          std::cout << *inscription << '\n';
      
          return 0;
      }
      

      实现此类函数的另一种方法是函数返回目标元素的索引而不是指向它的指针。

      例如

      #include <iostream>
      #include <cstring>
      
      template <size_t N>
      size_t fun( const char arr[][N] , size_t n ) 
      {
          size_t longer = 0;
          size_t longer_len = 0;
      
          if ( n != 0 )
          {
              longer_len = std::strlen( arr[longer] );
          }
      
          for ( size_t i = 1; i < n; ++i ) 
          {
              size_t len = std::strlen( arr[i] );
      
              if ( longer_len < len )
              {
                  longer = i;
                  longer_len = len;
              }
          }
      
          return longer;
      }
      
      int main() 
      {
          const size_t N = 100;
          char arr[][N] = 
          { 
              "Saturn", "Venus","Mars", "Earth", "Neptun" 
          };
      
          const size_t M = sizeof( arr ) / sizeof( *arr );
      
          size_t inscription = fun( arr , M );
      
          std::cout << arr[inscription] << '\n';
      
          return 0;
      }
      

      但由于该程序是 C++ 程序,因此实际上您不需要编写自己的函数。您可以使用标头 &lt;algorithm&gt; 中声明的标准算法 std::max_element 和相应的 lambda 表达式,如

      #include <iostream>
      #include <cstring>
      #include <iterator>
      #include <algorithm>
      
      const size_t N = 100;
      
      
      int main() 
      {
          char arr[][N] = 
          { 
              "Saturn", "Venus","Mars", "Earth", "Neptun" 
          };
      
          auto inscription = std::max_element( std::begin( arr ), std::end( arr ),
                                               []( const auto &s1, const auto &s2 )
                                               {
                                                  return std::strlen( s1 ) < std::strlen( s2 );
                                               } );
      
          std::cout << *inscription << '\n';
      
          return 0;
      }
      

      程序输出同上图

      Saturn
      

      【讨论】:

        【解决方案5】:

        我建议将指针返回到原始数组而不是复制。 这是通过引用而不是按值传递数组的替代方法(这很昂贵)。

        #include <iostream>
        #include <cstring>
        
        // make it a function template to accept arrays of different sizes
        template<size_t N, size_t L>
        char* fun(char (&arr)[N][L]) {                 // pass by reference
            char* longest = arr[0];                    // make a pointer to the first
            size_t longest_len = std::strlen(longest); // and store its length
        
            for(size_t i = 1; i < N; ++i) {
                // check if a longer C string is found
                if(size_t alen = strlen(arr[i]); alen > longest_len) {
                    // store the new length and a pointer to the new C string
                    longest_len = alen;
                    longest = arr[i];
                }
            }
            return longest; // return pointer into the original array
        }
        
        int main() {
            char arr[][100] = { "Saturn", "Venus","Mars", "Earth", "Neptun" };
            char *inscription = fun(arr);
            std::cout << inscription << '\n';     // Saturn
        }
        

        不过,使用std::vectorstd::string 会更容易,更不容易出错。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-11-29
          • 2015-10-01
          • 2020-07-24
          • 2011-04-21
          • 2011-09-04
          • 2015-02-03
          • 2011-07-27
          相关资源
          最近更新 更多