文字列のメモリ保持期間とポインタについての疑問

このQ&Aのポイント
  • 文字列のメモリ保持期間とポインタについて説明します。
  • ポインタで確保された文字列のメモリは明示的に開放する必要があります。
  • 文字列を返却したり、他のオブジェクトに格納する場合は注意が必要です。
回答を見る
  • ベストアンサー

文字列のメモリ保持期間とポインタについてわからないので教えてください。

文字列のメモリ保持期間とポインタについてわからないので教えてください。 よくポインタの説明に、文字列を使った下記のようなサンプルコードが紹介されます。 char* s; s = "abcdefg"; printf("%s",s); (http://www2.netf.org/pointer3.html から引用) この"abcdefg"により確保された領域がいつまで保持されるのかわかりません。 ・これを実行しているメソッドを抜けるまでなのか? ・free(s)するまでなのか?(free(s)しなければいけないのか?) この例だとprintfして終わっていますが、sを戻り値として返却して他で利用したり、オブジェクトを生成して、そのメンバ変数に obj1->field1 = "value"; というように格納して利用することとか考えると、領域は勝手に開放されず、やっぱり明示的にfreeするということでしょうか? freeしないといけない、なんて記述も見たことがなくよく理解できずにいます。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.2

場合によります。 >char* s; >s = "abcdefg"; >この"abcdefg"により確保された領域がいつまで保持されるのかわかりません。 >・これを実行しているメソッドを抜けるまでなのか? >・free(s)するまでなのか?(free(s)しなければいけないのか?) この場合は、プログラムがメモリにロードされた時点でメモリ上に"abcdefg"が配置され、 その先頭アドレスを char型のポインタ変数sに代入しているだけです。 # 「文字列リラテル」で検索されるとよいでしょう。 で、メモリ上に配置され"abcdefg"は、プログラムが終了するまで有効ですから解放する必要はありません。 # ちなみに「定数」扱いになりますので普通は書き換えできません。 >オブジェクトを生成して、そのメンバ変数に >obj1->field1 = "value"; >というように格納して利用する 実装にもよりますが…たいていクラス内で「内容を変更する」必要がある場合は、領域を確保して「コピー」しているかと。 free()が必要なのは、malloc()やcalloc()等で明示的に確保した場合…になります。 標準関数でどの程度あるかは不明ですが… 「呼び出し元が解放の責任を負う」という作りの関数を使用した場合は、当然free()は必要ですが。 # strdup()とか。

yukinori_111
質問者

お礼

ダブルクォートで作成した文字列は静的な定数として扱うんですね。 文字列の内容を変更するような場合には、メモリを確保してそこに内容をコピーしてから使用するというのは初耳でした。

その他の回答 (2)

回答No.3

> この"abcdefg"により確保された領域がいつまで保持されるのかわかりません。 "abcdefg"は文字列リテラルとしてソースコードに直書きされています。 こういうものはプログラムがメモリ上にロードされた時に、静的なメモリ空間に割り当てられます。 (PCだと実行時にRAM上にロードされますが、マイコン用の組み込みソフトなどではROM上のメモリ空間に割り当てられることもあります) したがって、このメモリ領域はプログラムが実行された時から終了するまで保持されます。 もっとも、"abcdefg"はずっと存在しますが、それを指してるポインタ変数「s」はローカル変数なので、関数を抜けた時点で消滅します。(static宣言されている場合は別ですが) そういうわけで、関数の戻り値で他に渡しても構いませんし、free()する必要はありません。

yukinori_111
質問者

お礼

ダブルクォートで作成した文字列は動作環境によって適切な領域に保持されるんですね。 ありがとうございました。

  • Yanch
  • ベストアンサー率50% (114/225)
回答No.1

文字列がリテラルの場合、生存期間は、プログラムをメモリに読み込んだ時点から、 プログラム終了時までです。 リテラルをfreeしたりしちゃいけませんよ。 プログラム終了時に、自動的に開放されます。

yukinori_111
質問者

お礼

ダブルクォートで作成した文字列はずっと保持されるのですね・・、知りませんでした。

関連するQ&A

  • 文字列を表すための配列とポインタ

    文字列を表すための配列とポインタ  配列とポインタは同様に扱えるもの、と思って、次のプログラムを作りました。処理系は、Visual Studio 2010 コマンドプロンプトです。 #include <stdio.h> void main(void) { char a[256]; char *b; printf("文字列を入力してください。\n"); printf("例「abcde」\n\n"); printf("配列型文字列を使います。\n"); scanf("%s", a); printf("文字列は%sです。\n\n", a); printf("ポインタ型文字列を使います。\n"); scanf("%s", b); printf("文字列は%sです。\n", b); }  すると、まずコンパイル時に、 「warning C4700: 初期化されていないローカル変数'b'が使用されます」 と表示されました。そして、実行すると、「配列型文字列」の方は問題ないのですが、「ポインタ型文字列」の方の実行後に、 「x.exeは動作を停止しました。 問題が発生したため、プログラムが正しく動作しなくなりま した。プログラムは閉じられ、解決策がある場合は Windowsから通知されます。」 と表示され、エラーとして終了してしまいます。 「char *b;」 と宣言するところが問題のようですが、なぜなのかが分かりません。どなたか、解説をお願いします。

  • 文字列リテラルの途中の文字を指すポインタについて

    文字列リテラルの途中の文字を指すポインタについて 下記のプログラムで途中の文字を指すポインタは、&s1[7]で 書かれていますが, s1+7と書けないでしょうか、問題点を教えてください。; int main(void) { char *s1 = "Bohyo takahoshi"; char *s2 = &s1[7]; printf("フルネームは%sです\n",s1); printf(フアミリールームは%sです\n",s2);

  • メソッド間の文字列の受け渡し

    初歩的な内容ですが、混乱してしまっているので、どなたか教えてください。 呼び元のメソッドで文字列を設定した文字列を呼び先subで取り出したいのですが、 アドレスから文字列を取り出すにはどうすればいいのでしょうか? #include <stdio.h> main() { char abc[]="ABC"; printf("%s\n", abc); sub(abc); /* 文字列abcのアドレスを値渡し */ printf("%s\n", abc); } sub(char *abc) /* 文字列abcのアドレスをポインタとして値受け取り */ { }

  • 数値→文字列変換関数

    ・数値を文字列化する関数StoAを作成する。 書式:char *StoA(short nVal); 引数:short nVal; 文字列化する数値 戻り値:数字文字列のポインタ 処理:nValで与えられたshort型の数値を文字列に変換し、そのポインタを返す。 呼び出し側の書式は以下の通り。 void main(void) { char *pc; pc = StoA(123); printf("%s\n", pc); pc = StoA(-1234); printf("%s\n", pc); } です。自分で途中までしたので見てください。 #include <stdio.h> cahr *StoA(short nVal); void main(void) { char *pc; pc = StoA(123); printf("%s\n", pc); pc = StoA(-1234); printf("%s\n", pc); } char *StoA(short nVal) { ここからがわかりません。どなたか助けて下さい。

  • 数値→文字列変換関数

    ・数値を文字列化する関数StoAを作成する。 書式:char *StoA(short nVal); 引数:short nVal; 文字列化する数値 戻り値:数字文字列のポインタ 処理:nValで与えられたshort型の数値を文字列に変換し、そのポインタを返す。 呼び出し側の書式は以下の通り。 void main(void) { char *pc; pc = StoA(123); printf("%s\n", pc); pc = StoA(-1234); printf("%s\n", pc); } です。明日までの専門学校の課題なのでどうか、どなたか助けて下さい。

  • 文字列 ポインタ

    3つの文字ポインタを作成し,最初のポインタが「one」を,二番目のポインタが「two」を,三番目のポインタが「three」をさすように初期化するプログラムを作成しなさい.次にこれらの3つの文字列の順列をすべてプログラムに表示させなさい. という問題で順列をうまく並べる方法がわかりません.手打ちでprintを6個作ることはできますが... うまい方法があるかないか,どのような方法か教えてください.よろしくお願いします. #include<stdio.h> int main(void) { char *a,*b,*c,*t; int i; a="one"; b="two"; c="three"; printf("%s\t%s\t%s\n",a,b,c); return 0; }

  • 文字列の探索

    ファイル名を指定して文字列の探索を行うというプログラムをC言語で作成したのですが、 コンパイルのときに警告で「問題のあるポインタの変換(関数 main )」と出て、うまい具合に動きません。改良点を教えてください。 #include<stdio.h> #include<string.h> #include<stdlib.h> unsigned char *s1; unsigned char *s2; unsigned char *cp; FILE *fp; char fname[64]; void TestStrStr(void); main(){ s1 = calloc(256, sizeof(unsigned char)); s2 = calloc(256, sizeof(unsigned char)); printf("Input Filename..."); scanf("%s",fname); while(1){ fp = fopen(fname, "r"); if(fp == NULL){ printf("ファイルを開くことができません...\n"); printf("Input Filename..."); scanf("%s",fname); }else break; } s1=fp; // printf("文字列1を入力してください:"); // scanf("%s",s1); printf("文字列2を入力してください:"); scanf("%s",s2); TestStrStr(); return 0; } void TestStrStr(void){ cp = strstr(s1, s2); if(cp == NULL) printf("'%s'に'%s'のいずれの文字も含まれない.\n", s1, s2); else printf("'%s'の中に現れる'%s'という文字列は%d文字目にある.\n", s1, s2, cp - s1 + 1); free(s1); free(s2); }

  • プログラミング ポインタを使った文字列比較

    プログラミング ポインタを使った文字列比較 2つの文字列str1, str2を入力し,それらが等しければ0,等しくなければ1を返す関数str_compareを作り、返り値によって以下のように表示するプログラムを作れ。ただし,関数strcmpを使ってはならない。 文字列の入出力はmain関数で行い,関数str_compareの仮引数にはポインタ変数を宣言し,ポインタと間接演算子*を用いた処理を行うこと。 % ./a.out input str1 = Worldcup input str2 = Worldcup same strings % ./a.out input str1 = World input str2 = cup different strings この問題に私は次のようにプログラミングしました。 #include <stdio.h> #define MAX 100 int str_compare(char *, char *); main() { char str1[MAX], str2[MAX]; printf("input str1 = %s", str1); scanf("%s", str1); printf("input str2 = %s", str2); scanf("%s", str2); str_compare(str1, str2); if (str_compare(str1, str2) == 0) printf("same strings\n"); else if (str_compare(str1, str2) == 1) printf("different strings\n"); } int str_compare(char *s1, char *s2) { int i; for (i = 0; s1[i] != '\0'; i++) { if (s1[i] != s2[i]) { break; } } if (s1[i] == s2[i]) { return 0; } else { return 1; } } これで実行したところ、「input str1 =」の右のスペースが文字化け?してしまいます。(半角カタカナや記号が出る)ただ、その後に文字列を入力すると、正しく機能します。 これは何が悪いなのでしょうか、どなたか教えてください。

  • 文字列の受け渡し

    先ほど質問したものですが、お願いします。 関数で戻り値として、文字列を扱う場合、 char* sendstr(void){ char* mychar="HELLO!!\n"; return mychar; } ならうまくいきますが、 char* sendstr(void){ char mychar[]="HELLO!!\n"; return mychar; } だと、うまくいきません。 配列の場合、mycharで、ポインタと なると、思うのですが。 後者の方が、分かりやすそうですが、 だめなのでしょうか。 (char*は文字型のポインタで、文字列 へのポインタになるのでしょうか)。

  • 文字列の途中に「0」がある場合の文字出力について

    C言語初心者です。宜しくお願い致します。 char ss[10]; /*【1】0ナシの文字列*/ strcpy(ss,"abcdefg"); printf("%s\n",ss); /*【2】0アリの文字列*/ strcpy(ss,"abc0efg"); printf("%s\n",ss); /*【3】0アリ(NULL文字アリ)の文字列*/ strcpy(ss,"abc\0efg"); printf("%s\n",ss); 【2】、【3】の文字列を最後(~fg)まで出力させるには、 どうしたら良いのでしょうか。 (0や¥0を、文字情報の一部として扱いたい場合、という意味です。) 宜しくお願い致します。

専門家に質問してみよう