2009-03-15 31 views
2

faqと私が見つけることができるすべてを読んだ後、私はまだ混乱しています。私はこの方法で初期化されるchar型のポインタがある場合:ポインタに値を割り当てることができないのはなぜですか?

char *s = "Hello world!"

を文字列には、読み出し専用メモリであり、私はこのようにそれを変更することはできません。「Wello世界を作るために

*s = 'W'; 

! "これは私が理解していますが、私の人生では、読まないようにする方法を理解できません。ポインタの代わりに配列を使用する必要がありますか? hereのように?

これは私のコードです:

char *s = str; 
char *e = s; 
while (*e != '\0') 
e++; 
e--; 
char *temp; 
//Swop the string around 
while (s <= e) { 
    *temp = *s; 
    *s = *e; 
    *e = *temp; 
    e--; 
    s++; 
} 

エラーメッセージがちょうどセグメンテーションフォールトです。これが本当にばかげた質問であれば、事前にお詫び申し上げます。

ありがとうございました。すべてのあなたのアドバイスを取った後、私はこれを取得:

void something(char * str) { 
    char *store = str; 
    char *s = new char[strlen(str) + 1]; //Allocate memory. Nice one. 
    strcpy(s, str); 
    char *e = new char[strlen(str) + 1]; 
    strcpy(e, str); 
    while (*e != '\0') 
     e++; 
    e--; 
    char temp; //no longer a pointer 
    while (s <= e) { 
     cout << *e; 
     temp = *s; 
     *s = *e; 
     *e = temp; 
     e--; 
     s++; 

    } 
    delete [] e; 
    delete [] s;   
} 

しかし、関数の最後の削除は、独自のセグメンテーションフォールトを引き起こしているようです。どうして?

問題は、ポインタがインクリメントされた後にeおよびsポインタにアクセスしたことによるものです。

void something(char * str) { 
    char *s = new char[strlen(str) + 1]; 
    strcpy(s, str); 
    char temp; 
    int j = strlen(str) - 1; 
    for (int i = 0; i <= strlen(str)/2; i++) { 
     cout << s << endl; 
     temp = s[i]; 
     s[i] = s[j]; 
     s[j] = temp; 
     j--; 
    } 
    delete [] s; 
} 
+0

私がこれを読んでいるところでは、あなたの* = 'W'はあなたができないことを知っていることの一例に過ぎません。以下のコードとは何の関係もありません。あなたが実際に助けてくれるものは何ですか?ほとんどの回答が最初の例に焦点を当てているように思われる – jalf

+0

はい、私はそれができないことを知っています:(私はそれを正しく行う方法について疑問を抱いていました。 – pypmannetjies

+0

正確に何をするのですか?私はあなたの質問が何であるかまだまだ不明です。文字列を逆にしようとしていますか? "* s =" W "一部の質問は質問自体と関連があります また、削除によってsegfaultsが発生した場合でも、それらを投稿する必要があります。 – jalf

答えて

6

これを変更する最も簡単な方法は、ストレージのアレイを作成してその中に文字列をコピーすることです。例えば

char buf[128]; 
const char *src = "Hello World"; 
strncpy(buf, src, 127); // one less - we always 0-terminate 
buf[127] = '\0'; 

// you can now modify buf 
buf[0] = 'W'; 

あなたのコードが動作しない理由は、あなたが文字列のコピーのための任意のメモリを割り当てられていないということです - あなただけの同じ読み取りに第2のポインタを作りました - ただの記憶。 (そして、それをコピーしようとしましたか?コードの残りの部分が何をしているのかよく分かりません)。読み取り専用でないメモリをどこかに置く必要があります。あなた自身でループを書くのではなく、新しいメモリ。あなたはまた、malloc関数を使用することができ、事前に文字列の長さを知らない場合には

(、より良い、または何drschnzの回答を行うと言うと、使用 新しいのchar []):

const char *src = "Hello world"; 
char *buf = malloc(strlen(src) + 1); // or = new char[strlen(src) + 1]; 
strcpy(buf, src); 
// you can now modify buf 
// later, you need to free it 
free(buf);        // or delete [] buf; 
また

、あなたがC++のを使用している場合、あなただけのstd ::文字列を使用することができます。

std::string myString("Hello world"); 
myString[0] = "W"; 

希望に役立ちます。

+0

'char * buf [128];'最初のブロックの例では、128文字の配列ではなく128個の配列の配列を返します。アスタリスクを削除して、あなたは良いです。 –

+0

あなたの例には「typo」があります:「char * buf [128];」 "char buf [128];"にする必要があります。 (すなわち、charの配列の代わりにcharのポインタの配列を持っています) –

+0

あなたは1秒で私を打ちます>< –

7

試してください:あなたがバッファに文字列をコピーしたい場合は、それが必要その後、独自の文字列のコピーを作成する必要がある場合は

char src[] = "Hello world"; 
src[6]  = 'W'; 

-- // or 

char buffer[] = "Hello world"; 
char* src  = buffer; 
src[6]   = 'W'; 

は、その後のstrcpy()やはstrncpy()

char buffer[20]; 
char const* s = "Hello World" 

strcpy(s,buffer); 

を使用

char buffer[20]; 
char const* s = "Hello World"; 

// OK this is not the perfect solution but it is easy to read. 
for(int loop = 0;s[loop] != '\0';++loop) 
{ 
    buffer[loop] = s[loop]; 
} 
buffer[loop] = '\0'; 
+0

forループ内のconst&とint iをチェックする必要があります。質問には "C"というタグが付きます –

+0

char const&s = "Hello World"; // AFAIKこれは不正です(CまたはC++)。 const char *をchar const&(またはconst char&またはchar const *)にキャストすることはできません。また、 'loop'は変数の奇妙な名前です。私は「私」を提案する。 – strager

+0

質問はもともとC++とタグ付けされていました。誰かがそれを変更しました。 – pypmannetjies

2

ポインタは読み取り専用ではありません。 (文字列データ自体はありますが、それを指すポインタは自由に変更できます)しかし、ポインタに文字を割り当てることは、あなたが期待することをしません。

一般に、ポイントに割り当てることができるのはアドレスだけです。値を割り当てることはできず、値のアドレスだけを割り当てます。

文字列が特殊なため、文字列リテラル(「hello world」など)も例外です。そのうちの1つをポインタに割り当てると、その文字列へのポインタが得られます。しかし、一般的には、ポインタにアドレスを割り当てます。

もう1つのポイントは、C++の文字は整数データ型です。それらは、キャスティングを必要とせずに整数として扱うことができます。 私はint i = 'W'できますし、コンパイラは不平を言うことはありません。

ポインタに「W」を割り当てるとどうなりますか?これは整数値として 'W'をとり、これがアドレスであると仮定します。 'W'はASCII値127を持っているので、あなたは効果的にアドレス127を指すようにポインタを設定しています。これは意味をなさないものです。

私はあなたのコードとは関係がありません。 tempは有効なデータを指していないようです。未定義のアドレスを指すポインタを宣言します。こんにちは世界 『:そして、あなたは「。のように、strポイントであれば、文字列リテラルに、しかし

char temp; // not a pointer. We want a character to store our temporary value in 
while (s <= e) { 
    temp = *s; // note, no * on temp. 
    *s = *e; 
    *e = temp; // note, no * on temp. 
    e--; 
    s++; 
} 

sポイント幾分良好に動作するはずです以下、それが指すところはどこでも、私は価値を書きたい』と言います文字列データ自体が読み込み専用であるため、コンパイラはそれを強制することはできませんが、未定義ビヘイビアの土地に移動したことがあります。ローカルバッファーを他の答えの1つとして示しています。

ポインタのセマンティクスについては混乱しているようですが、アドレス(または整数などのアドレスに変換できるもの)をポインタに割り当てると、ポインタはそのアドレスを指します。ポイント先のデータは変更されません。 ポインタを宣言しても、何か意味のあるものを指しているわけではありません。 charを格納する場合は、char変数を宣言します。ポインタはデータを格納せず、他の場所に割り当てられたデータを指しています。

あなたの更新されたコードに

編集 コメントと修正:ちょうど参照用

void something(const char * str) { // let the function take a pointer to a non-modifiable string, so add the const. Now it's clear that we're not allowed to modify the string itself, so we have to make a copy. 
    char *s = new char[strlen(str) + 1]; // Since the original string is const, we have to allocate a copy if we want to modify it - in C, you'd use malloc(strlen(str)) instead 
    strcpy(s, str); 
    char *e = s; // make e point to the start of the copied string (don't allocate two copies, since e and s are supposed to work on the same string 
    while (*e != '\0') { // add braces so it's clear where the loop starts and ends. 
     e++; 
    } 
    e--; 

    while (s <= e) { // the loop condition wouldn't work if s and e pointed to separate copies of the string 
     cout << *e; // why? I thought you just wanted to reverse the string in memory. Alternatively, if you just want to print out the string reversed, you don't need to do most of the rest of the loop body. In C, you'd use printf instead of *e 
     char temp = *s; // might as well declare the temp variable when you need it, and not before 
     *s = *e; 
     *e = temp; 
     e--; 
     s++; 

    } 
} 

、およびC++対Cについてのコメントに反応して、ここで私は、文字列を逆にする関数を記述したい方法ですC++で:

std::string revert_string(const std::string& str) { 
    return std::string(str.rbegin(), str.rend()); 
} 

またはイン場所の文字列を戻す:

std::string revert_string(const std::string& str) { 
    std::reverse(str.begin(), str.end()); 
} 
+0

私は混乱しています:)私はちょうどC++で始まっていますが、先にtempを変更しようとしましたが、それは問題を解決しませんでした。しかし、ありがとう、それは今働いているようです。 – pypmannetjies

+0

ここの用語は混乱しているようです。指さしても弦は特別ではありません。これは実行時にポインタをつかむことのできるものの一つです。コンパイラは、(厄介な)キャストなしでintをint *に変換することはできません。 (あなたはptrdiff_tなどを使っているはずです) – strager

+0

申し訳ありませんが、私は文字列が特別であるという意味ではありませんでしたが、文字列リテラルはやや異なった扱いをしていますので、値のように見えますポインタに割り当てることができます。それ以外のものでは、明示的に値のアドレスを取る必要があります。 – jalf

1

技術的には、あなたがより正確にそのように書かれています:

const char *s = "Hello world!" 

あなたが実際にしたいと、そのようなものです:

char s[] = "Hello world!" 

数行続くのは、あなたがより多くを理解することに役立つことがあります。

const char *p = "Hello World"; 
char q[] = "Hello World"; 
printf("%d %d", sizeof(p), sizeof(q)); 
// p[0] = 'W' // INVALID 
q[0] = 'W'; // valid 
+0

ありがとうございますが、私はこれを知っています。私は、配列を使う以外の方法があるかどうかを知る必要があります。 – pypmannetjies

+0

ポインタ、文字列、配列の違いは何ですか? –

+0

@jleedev、ポインタが何かを指しています。文字列は文字の配列です。配列(データ型)は、データの配列に対する暗黙的なポインタです(*正確にはポインタのように振る舞いません)。 – strager

0

あなたの削除は、ポインタを変更したためにフォルトを生成します。新しいものの元の場所を保存し、それを削除する必要があります。アロケーションテーブルにない場所を削除しようとしました。 ポインタの値を変更する場合は、別のchar * temp = t;を作成してください。文字列を反復処理するために使用します。

0

#文字列のコピーを作る関数 "strdup()"があります。あなたのmallocで "+1"を忘れないようにします。

char* source = "Hello World"; 
char* dest = strdup(source); 
+0

標準ではないC(ただし、POSIXです)。しかし、OPは現実のソリューションではなく概念ソリューションを探していると思います。彼はなぜ何かが行動するのを知ろうとしています。 – strager

+0

いいえ、それはposixです。それでも、それが利用できない場合は、自分で書くべきことのようなものです。コードを毎回手動で書き出すことは良くありません。 –

関連する問題