2012-01-09 227 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