2012-01-09 228 views
2

我知道我可以通过str.c_str(), 来做到这一点,但我不想要一个字符常量。我想要一个字符,以便我可以进行一些修改。将字符串转换为字符

char* removeDup(char *s) 
{ 


     int len = strlen(s); 
     int p,q, idx = -1; 
    for(p = 0; p< len; p++) 
    { 
    char temp = s[p]; 
    bool flag = true; 
    for(q=0;q<p;q++) 
    { 
     if(s[q] == temp) 
     { 
      flag = false; 
      break; 
     } 
    } 
    if(flag == true) 
    { 
     s[++idx] = temp; 
    } 
} 
    s[++idx] = '\0'; 
    return s; 
} 

如果我调用这个函数如下,我得到错误;

string s = "abcde"; 
removeDuplicate(s.c_str()); 

我需要转换这个schar而不是const char

+10

我的建议是在'而不是string'并跳到'字符传递*'完全 – Default 2012-01-09 13:25:05

回答

5

要获得从std::string底层数据可以使用:

string::data()string::c_str(),都返回一个const char *

在任何一种情况下,返回的数据都是const char *,因为它的内存分配给用户程序不允许修改的某个只读实现定义区域中。任何尝试修改返回的const char *将导致未定义的行为

所以你不能也不应该(通过const_cast)修改返回的字符串。

的唯一正确途径通过创建一个新char*实现这一目标,分配它,并从const char*中的内容复制:

std::string myString = "blabla"; 
char* myPtr = new char[myString.size() + 1]; 
myString.copy(myPtr, myString.size()); 
myPtr[myString.size()] = '\0'; 
+0

谢谢,但我不希望使用任何额外的缓冲 – Roger 2012-01-09 13:24:44

+0

@Roger然后用'的const_cast '但它是一个坏主意。正确的解决方案是按照@Luchian Grigore的建议复制数据。 – 2012-01-09 13:26:28

+1

@罗杰好,那是不可能的。 C型转换为'char *'会破坏程序,因为它会导致未定义的行为。为什么不使用std:string的函数来实现你想要的? – 2012-01-09 13:26:31

2

我会建议把缓冲区的副本,调用你的函数,然后将原始字符串设置为新的字符缓冲区。类似于:

std::string str("some string"); 
char tmp[str.length() + 1]; 
memset(tmp, 0, sizeof(tmp)); 
copy(str.begin(), str.end(), tmp); 
str = removeDup(tmp); 

直接使用由c_str()返回的const缓冲区并修改它会造成麻烦。缓冲区由字符串对象拥有,您应该考虑将其修改为破坏封装并取决于最小实现。

+0

不仅仅是打破封装(这可能是一个可以解决的问题)抛弃const是一个有保证的未定义行为。 – 2012-01-09 13:35:32

+0

请注意,变长数组是C++的非标准扩展。如果你想要可移植性,使用'std :: vector '。 – 2012-01-09 14:18:33

0

我想你想从字符串这个方法:从字符串中的字符

复制序列: http://www.cplusplus.com/reference/string/string/copy/

如。如果你有一个字符串'str',你可以这样做:

char buf[str.len()+1] 
str.copy(buf, str.len()) 

//terminate with newline 
buf[str.len() = '\n'] 

希望有帮助。

1

只需复制它。

string str = "Hello"; 
char * cStr = new char[str.size()]; 
memcpy(cStr, str.c_str(), str.size()); 
+0

不要忘记在完成时删除动态数组(或更好地使用'std :: vector ')。另外,它看起来像问题中的邪恶函数需要一个以零结尾的字符串,所以使用'str.size()+ 1'来包含终止符。 – 2012-01-09 14:20:00

1

合法进行修改一个std::string的唯一方法是通过 它的成员函数(包括它们间接 提供接入路径)。因此,你应该重写你removeDup采取 std::string::iterator作为参数,像:

std::string 
removeDup(std::string& original) 
{ 
    std::string::iterator current = original.begin(); 
    std::string::iterator end = original.end(); 
    while (current != end) { 
     end = std::remove(current + 1, end, *current); 
     ++ current; 
    } 
    original.erase(end, original.end()); 
    return original; 
} 

(我认为这确实你原来的代码做我不能肯定, 什么,因为我真的不能图你的原始代码。)

从设计角度来看,这是丑陋的;你可能要经过 std::string const&,并返回一个新std::string

std::string 
removeDup(std::string const& original) 
{ 
    std::string results; 
    std::bitset<UCHAR_MAX + 1> alreadySeen; 
    for (std::string::const_iterator current = original.begin(); 
      current != original.end(); 
      ++ current) { 
     if (! alreadySeen.test(static_cast<unsigned char>(*current))) { 
      results += *current; 
      alreadySeen.set(static_cast<unsigned char>(*current)); 
     } 
    } 
    return results; 
} 

你想从一个std::stringchar*唯一的一次是通过 它遗留代码(或C)。在这种情况下,std::string::c_str()是 批准的方法;如果要调用的函数需要一个char*, 则:

  • 如果该功能实际上并没有修改字符串(它不是const的 正确的,但是这是许多C函数的情况下),然后使用 const_cast上的std::string::c_str()的返回值,否则

  • 必须分配一个本地缓冲器,并把它传递:

    的std ::矢量localBuffer(s.begin(),s.end()); localBuffer.push_back('\ 0'); legacyFunction(& localBuffer [0],localBuffer.size());

0

在“可能”的境界,而不是“明智”,你可以这样做:

std::string str("foo"); 
str = removeDup(std::auto_ptr<char>(strdup(str.c_str()).get()); 

但在性病方面改写:: string的效果会更好。

+1

虽然这确实假定malloc和new是字符的同义词。 – 2012-01-09 16:24:59