【问题标题】:How to * char + * char in c++?如何在 C++ 中 * char + * char?
【发布时间】:2013-11-29 12:54:21
【问题描述】:

这是我最近遇到的一个问题。

如果我要做这样的事情:

string str1 = "some";
string str2 = "thing";
cout << str1 + str2 << endl;

我会得到下一个输出:something

但我只有这个:

char *chr1 = "How do"
char *chr2 = "I do this?"

我需要得到以下输出

那么,我该怎么做?是的,我真的需要char *

【问题讨论】:

  • 如果您所做的只是打印它们,您可以这样做 cout &lt;&lt; chr1 &lt;&lt; chr2 &lt;&lt; endl; 或者如果您真的想添加空格:cout &lt;&lt; chr1 &lt;&lt; ' ' &lt;&lt; chr2 &lt;&lt; endl;
  • 不只是打印,我需要获取 char * 变量作为结果容器,我需要它来进一步使用。
  • 您是否考虑过使用std::string 并在需要const char* 时只使用它的c_str() 方法?
  • 因此,如果您尝试在函数中执行此操作并且尝试执行return combined.c_str();,则返回的const char* 将超出范围。 @user2890591 我注意到你在尝试@Paranaix 的解决方案时说你的“应用程序崩溃了”。我的建议是你返回一个std::string 并调用c_str()每次你想使用const char*

标签: c++ pointers merge char


【解决方案1】:

您需要创建大小为strlen(chr1) + strlen(chr2) + 1 + 1 的缓冲区,(最后+1,因为strlen 返回的字符串长度不带空终止符,但c-string 应以空终止符结尾)然后将第一个字符串复制到新缓冲区中str(n)cpy 然后使用str(n)cat

char* buffer = new char[strlen(chr1) + strlen(chr2) + 1 + 1];
strcpy(buffer, chr1);
strcat(buffer, " ");
strcat(buffer, chr2);
// use buffer
delete[] buffer;

【讨论】:

  • 由于 OP 是新手,为什么分配+1 字符可能是个好主意?
  • 如果需要删除,不如在 C++ 中使用 boost::unique_ptr 或在 C++11 中使用 std::unique_ptrstd::make_unique
  • sprintf 是 cpy/cat/cat 部分的一个很好的替代品。 IE。 sprintf(缓冲区,“%s%s”,chr1,chr2);并且对于小问题很方便,比如如果你想在它们之间折腾一个空间。
【解决方案2】:

尽管 strcat() 可能是 ScarletAmanranth 已经提到的最佳解决方案,但还有另一个解决方案。

也可以先将 c-strings 转换为 std::string's,对它们执行任何所需的操作,然后将结果转换回 c-string。在某些情况下,这可能更适合您的需求。

示例:

const char* str1 = "foo";
const char* str2 = "bar";

std::string combined = std::string(str1) + str2; // notice std::string + char* => std::string

const char* result = combined.c_str();

优点:

  • 可以写成 oneliner,无需进一步声明缓冲区等。
  • 可能允许通过std::string 方法和相关函数更轻松地进行操作

缺点:

  • 额外开销
  • 只能获取const char*,如果需要char*,则必须再次复制c字符串

考虑返回的const char* 直接指向std::string 对象的内部缓冲区。因此,只要std::string 对象没有超出范围,指针就保持有效。因此,将其与 const char* result = (std::string(str1) + str2).c_str(); 之类的临时对象一起使用是一个非常糟糕的主意(而在函数调用中编写类似的东西是合法的,因为临时对象会一直保留到调用返回)。

【讨论】:

  • c_str()No-throw guarantee。确保指针仅在 std::string 保持有效时保持有效。获取的指针直接指向std::string对象的缓冲区。如果与临时工一起工作,这一点尤其重要。我想我会在我的回答中包含这个
  • 如果你对 c_srt() 返回的字符串做一个 const_cast,然后修改 char*,然后再次使用 c_str() 会发生什么?
  • @lucas92 你不能那样做,这就是为什么字符串类返回一个 const char*
  • @lucas92 当仅从标准中看到时,它只是未定义的行为,因为如果您更改 const-casted 对象就是这种情况。从技术上讲,我认为只要您不更改字符串的大小,一切都会正常工作。所以用char* 替换单个字符应该可以。顺便说一句,c_str() 可能会两次返回相同的地址。
  • 我这样做了,如果 const str 是可以接受的,它写起来很容易而且很快。如果 const 不好,那么你别无选择,只能使用其他技术
【解决方案3】:

在这种情况下,您需要使用strcat()
正如 cmets 中所指出的,您需要像 char[] 这样的东西作为新字符串的缓冲区。

【讨论】:

  • 但请注意,不能将问题中的任何字符串指针用作strcat 的目标。
  • 完成,应用程序在 strcat() 字符串处崩溃。
  • @user2890591 那是因为你做错了。这就是为什么建议使用 std::string 的原因。这更容易。
  • @user2890591 有一个答案包含对整个机器的准确(和正确)使用,看看它:)。
【解决方案4】:

由于这是 C++,因此必须有人提出我将要提出的建议。使用stringstream

#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <string.h>

using namespace std;

int main() {
    char *chr1 = "How do";
    char *chr2 = "I do this?";
    stringstream ss;

    ss << chr1 << chr2;
    string result = ss.str();
    char* final = (char*) calloc(result.size()+1, sizeof(char));
    strcpy(final, result.c_str());

    cout << final << endl;

    delete [] chr1, chr2, final;

    return 0;
}

calloc(int size, sizeof([type])) 调用会分配您保留最终char* 所需的所有内存。像这样,您可以以更 C++ 的方式将两个字符放在一起。但是,您想要做的更像是 C,但既然您在 C++ 中,不妨尽可能多地使用属于 C++ 一部分的方法。

【讨论】:

    【解决方案5】:

    首先不需要字符串连接;您可以继续使用流插入运算符 &lt;&lt; 执行有效的连接(而不是使用 + 来形成一个临时的 std::string 对象,然后流插入该结果字符串):

    std::string str1 = "some";
    std::string str2 = "thing";
    std::cout << str1 << str2 << std::endl;
    

    因为这是流的属性而不是字符串,所以您可以使用char* 输入来做到这一点:

    const char* chr1 = "How do "
    const char* chr2 = "I do this?"
    std::cout << chr1 << chr2 << std::endl;
    
    // Output: How do I do this?
    

    请注意,我为字符串文字添加了 必需 const;当且仅当您的 C 字符串不是由字符串文字初始化时,您才可以删除它。

    【讨论】:

      【解决方案6】:

      几个考虑:

      • 首先是you should declare chr1 and chr2 as const char *, not char *,因为尝试修改字符串文字是未定义的行为。
      • 其次,operator +关于指针涉及指针运算,char *在这方面并不特殊。如果需要连接字符串,则需要分配一个缓冲区,在其中一个接一个地复制两个字符串。
      • 现有答案使用普通的旧 C 函数(Paranaix 除外),但如果您制作了一个像 std::cout 这样使用的字符串流,那么在 C++ 中会更惯用:

        #include <string>
        #include <stringstream>
        std::ostringstream ss; ss << chr1 << " " << chr2;
        const std::string s = ss.str();
        const char *result = s.c_str(); // you can use this pointer during the scope of `s`.
        

      【讨论】:

      • "我需要 char*" -> "首先,你应该将 str1 和 str2 声明为 const char*" :)
      • @ScarletAmaranth,遵守良好实践永远不会太晚,字符串文字在 C 和 C++ 中都是 const 并且省略 const 是一个错误,在 C++11 中甚至非法。
      • Stackoverflow,唯一一个因原因被驳回的门户网站:)。
      • 如果我尝试这样做:*iNeedResultHere = result;我显然会得到“无法将类型为“cost char *”的值分配给类型为“char *”的实体,我知道 const_cast,但它没有帮助,iNeddResultHere(即 char *)包含不可读使用 const_cast 后的字符集。
      • @user2890591,在CC++ 中,执行char *x = "abc"; x[0] = 'd'; 之类的操作是未定义的行为,因此您永远不应该这样做。代码中的任何字符串文字都必须被视为不可变的。如果您想要可修改的字符数组,您必须分配一个缓冲区来复制它们,无论是strdup(C 风格)、new char[]...delete[](C++)、string(C++)等。或初始化为char x[] = "abc",因为它从字符串文字中初始化了一个由4个char组成的数组。
      【解决方案7】:

      通常答案是“使用 std::string”。

      是的,我确实需要 char *。

      不只是打印,我需要获取 char * 变量作为结果容器,我需要它来进一步使用。

      ...但在这种情况下:

      #include <cstring>
      
      std::size_t len1 = std::strlen(str1);
      std::size_t len2 = std::strlen(str2);
      // unique_ptr: automated lifetime management
      // 1 for '\0' terminator
      std::unique_ptr<char[]> buffer( new char[len1 + len2 + 1] );
      std::copy_n(str1, len1, buffer.get());
      std::copy_n(str2, len2, buffer.get() + len1);
      buffer.get()[len1 + len2] = '\0'; // after this, buffer.get()
                                        // points to your string
      

      【讨论】:

      • Sooo... 基本上而不是仅仅使用std::string 作为容器并调用c_str() 来获取const char* 你建议他使用std::unique_ptr&lt;char[]&gt; 作为容器并调用get() 获取const char*?
      • OP 指出他需要 char*。由于他没有具体说明为什么 std::string 不能正常工作,我们必须相信他的话。这是一个基于 char* 的解决方案,添加了 RAII“安全性”。OP 可以直接使用 char*,但它需要额外的一行(delete[] 调用),没有增加任何好处并且使代码更差/更不安全.
      • 我和下一个人一样爱std::unique_ptr,但我很难理解为什么与@Paranaix 相比,这将是一个好的解决方案。如果您要引入一个容器,为什么不使用正确的容器,对吧?
      • 我知道 - 通常我会简单地建议 std::string (就像我实际做的那样:))。也就是说,如果我要使用char*(如“not std::string”),我不会将 std::string::c_str 的结果存储到单独的变量中(向下传递堆栈是可以的)。否则,您最终会遇到生命周期问题(当变量 - 而不是持有指针的变量 - 超出范围时,内存缓冲区将失效。这是一个等待发生的非显而易见的错误(可能当第二个开发人员决定指针应该是也用于其他用途)。简而言之,代码不是自记录的。
      【解决方案8】:

      我分享了我的代码,以便能够在另一个 auto* 中添加“char*”的文本,而无需通过字符串或 cstring:

      #include <iostream>
      using namespace std;
      
       int leng(char* tx){
           long long int n = 0;
           while(true){
               if(tx[n] == '\0'){
                   break;
               }
               n += 1;
           }
               
           return n;
       }
      
      
      int main(){
          char* t = "sffdsdssd";
          char* t2 = "axgdfb";
          long long int num = leng(t)+leng(t2);
          char g[num] = {0};
          long long int n = 0;
          for(n = 0; n < leng(t); n++){
              g[n] = t[n];
          }
          long long int num1 = leng(t);
          for(n = 0;  n < leng(t2); n++){
              g[num1+n] = t2[n];
          }
          char* resultado = (char*)g;
          cout << resultado;
          return 1;
      }
      

      【讨论】:

        猜你喜欢
        • 2017-09-19
        • 2014-11-04
        • 2011-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-03
        • 2014-10-22
        相关资源
        最近更新 更多