2009-06-03 8 views
5

Cスタイルの文字列では、文字ポインタが指すメモリアドレスにcharをどのように割り当てるのですか?たとえば、以下の例ではnumを "123456"に変更したいので、pを0になっている数字に設定しようとしましたが、これを '4'で上書きしようとしました。ありがとう。文字列を変更するこのコードが機能しないのはなぜですか?

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    char* num = (char*)malloc(100); 
    char* p = num; 

    num = "123056"; 

    p = p+3; //set pointer to where '4' should be 
    p = '4'; 

    printf("%s\n", num); 

    return 0; 
} 
+0

可能な重複「のchar \ * s」のではなく、「文字の\ [\]」で初期化された文字列への書き込み時に[なぜ私がセグメンテーションフォールトを得るのですか? ](http://stackoverflow.com/questions/164194/why-do-i-get-a-segmentation-fault-when-writing-to-a-string-initialized-with-cha) – jww

答えて

12

コードは動作しないことを、単に行理由:

num = "123056"; 

が割り当てられたメモリから離れて指すようにnumを変更する(そして、彼らはもはや同じ場所ですのでpは、そのメモリを指して残っていません)を最も可能性の高い読み取り専用メモリに置き換えます。文字列リテラルに属するメモリを変更することは許可されていませんが、未定義の動作です。

あなたは以下のものが必要です。の

#include <stdio.h> 
#include <stdlib.h> 
int main (void) { 
    char *num = malloc (100); // do not cast malloc return value. 
    char *p = num; 

    strcpy (num, "123056"); // populate existing block with string. 

    p = p + 3;    // set pointer to where '0' is. 
    *p = '4';     // and change it to '4'. 

    printf ("%s\n", num); // output it. 

    return 0; 
} 
+0

また、メモリを解放する必要があります。 –

+2

これは良いフォームです@Igorですが、プログラムがすぐに終了しているので、必要ではありません。スニペットのアイデアは、すべての情報ではなく、関連する情報を伝えることです。それ以外の場合は、malloc()も同様に機能することを確認する必要があります。 – paxdiablo

0

ちょうど*p = '4'; ...を使用してください。あなたがすべての

+0

それを省略した作業。文字列 'num'は不変か何か?私はLinuxでCCでコンパイルしています。 –

+0

これは間違っています。 4ではなく4でなければなりません。 –

+0

はい、文字列リテラルは、読み取り専用とマークされているメモリセグメントに割り当てられており、書き込むattempは実行時エラーを引き起こします。 – sharptooth

13

まず、:

num = "123056"; 

あなたはmalloc()によって割り当てられたヒープ領域に文字列「123056」をコピーしていません。 Cでは、文字列リテラル値が一定としてそれを設定することと同じですchar *ポインタを割り当てる - とつまり同じ:

char str[] = "123056"; 

だから、あなたはちょうどあなたがにあなたの唯一の参照を放棄してきている達成してきたものmalloc()によって割り当てられた100バイトのヒープ領域。これは、後続のコードが正しい値を出力しない理由です。 'p'はまだmalloc()(割り当て時にnumが指しているので)によって割り当てられたヒープの領域を指していますが、numはこれ以上しません。

そのヒープ領域に文字列 "123056"をコピーしたとします。ここでそれを行う方法は次のとおりです。

strcpy(num, "123056"); 

これは、様々な理由のためのより良い習慣です、が:

strncpy(num, "123056", 100 - 1); /* leave room for \0 (null) terminator */ 

あなただけ行っていた場合:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int  main(void) { 
     char *num = malloc(100); 
     char *p = num; 

     strncpy(num, "123056", 100 - 1); 

     p = p + 3; 
     *p = '4'; 

     printf("%s\n", num); 

     return 0; 
} 

あなたが得ているだろう正しい結果:

123456 

この操作を契約することができ、次のようdeferencingにより、

p = p + 3; 
*p = '4'; 

...とポインタを反復避ける:

*(p + 3) = '4'; 

他のいくつかの注意事項:一般的な文体が、

  • 実際には、malloc()の戻り値を(char *)にキャストする必要はありません。 void *タイプの変換とアラインメントは、C言語によって保証されています。

  • いつも戻り値malloc()をチェックしてください。ヒープの割り当てに失敗した場合(つまりメモリ不足の場合)はNULLになり、その時点でプログラムは終了します。

  • 実装によっては、malloc()によって割り当てられるメモリ領域に特定の状況で古いゴミが含まれることがあります。

    memset(num, 0, 100); 
    
  • free()あなたのヒープに決して忘れない:常に割り当てた後、それをゼロにすることをお勧めします!この場合、プログラムは終了し、OSはゴミをクリーンアップしますが、慣れていなければ、すぐにメモリリークが発生します。

ので、ここでは、 "ベストプラクティス" バージョンです:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int  main(void) { 
     char *num, *p; 

     /* 
     * Don't take 1-byte chars for granted - good habit to get into. 
     */ 

     num = malloc(sizeof(char) * 100); 

     if(num == NULL) 
       exit(1); 

     memset(num, 0, sizeof(char) * 100); 

     p = num; 

     strncpy(num, "123056", 100 - 1); 

     *(p + 3) = '4'; 

     printf("%s\n", num); 

     free(num); 

     return 0; 
} 
+1

素晴らしいメモリ管理のヒントをありがとう。これらのヒントは、自動的なガベージコレクション言語から来た人には良いことです! –

+0

確かに!お力になれて、嬉しいです! –

+0

優秀な投稿!貴重な情報がたくさんあります。ありがとうございました。 –

0

はさて、あなたは、pはポインタ型である知っています。 char '0'のアドレスを格納します。 pに '4'の値を割り当てた場合。アドレスとして '4'が使用されます。ただし、アドレス '4'は不正です。 '*'演算子を使用すると、格納されているpに格納されているアドレスの値を取得できます。

+0

アドレス「4」は不正ではありません。実装では、0x00000034のメモリをかなり簡単に使用できます(32ビットワードの場合でも正しく整列されます)。 – paxdiablo

+0

さて、私はこのアプリケーションでは違法だと言った。これは未知のメモリアドレスです。 – Sefler

1

* pの問題に加えて、他にもメモリの使用に関する問題があることが指摘されています。不明な内容の100バイトのバッファが1つあります。文字列 "123056"とヌル終端文字を含む7バイトの別のバッファがあります。あなたはこれをやっている:

  1. numを
  2. pをNUMを指すように設定されている100バイトのバッファを指すように設定されています。つまり、100バイトのバッファを指します。
  3. numをリセットして7バイトのバッファを指すようにします。 pは、まだあなたは、あなたが同じバッファを印刷していない、あなたは7バイトのバッファから

を印刷するNUMを使用して100バイトのバッファ

  • を変更するために、Pを使用
  • 100バイトのバッファを指していますあなたが修正していること。

  • +0

    Bruceさん、ありがとうございました。あなたの説明は役に立ちましたが、Paxのstrcpyは本当にそれを明確にしました。 –

    関連する問題