• ベストアンサー

char*型が0x0を含む場合

char *str = {0x61, 0x62, 0x0, 0x64}; ができないから、 char *str = "abcd"; str[2] = 0; として、{0x61, 0x62, 0x0, 0x64} という文字列を作ってみた。 このポインタ str は解放する必要がない。 malloc( ) で確保したなら free( ) する必用がある。 普通のポインタは、もしかしたら 0x0 までしか 確保されていないのかなと思いました。 この場合では、str[3] == 0x64 だという結果になったけど、 それは str[2] の次のデータが 0x64 だったわけで、 str[2] に 0x0 が入った時点で、str[3] 以降の領域は str とは無関係かもしれないと思いました。 つまり、char*型は、0x0 までの部分だけを確保し、 この例のソースでは、str[3] 以降の領域は確保されていないから 後で、知らないうちに値が変わっている可能性がある。 という想像をしてみたけど、あってますか?

  • A__
  • お礼率59% (194/328)

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

  • ベストアンサー
  • honiyon
  • ベストアンサー率37% (331/872)
回答No.1

こんにちは、honiyonです。  ハズレです。  最初に 4byte確保したなら、str[2] = NULL; としても 4byte確保されています。  char*型はあくまで「char型へのポインタ」であり、メモリの操作は行いません。  0x00 も立派な「データ」ですよ。  char* = 文字列データ という意味合いが強いですが、あくまで char型は「0~255の整数型」であり、それ以外の用途にも使用される事があります。 char* でメモリを確保し、バイナリデータを扱う事だって出来ます。  参考になれば幸いです(..

A__
質問者

お礼

ありがとうございます。 ハズレでしたか。 メモリの操作は行わないという意味が分かりませんでした。 char *str = "abcd"; で5バイト確保される。 そして str を使う。 必要なくなったら、確保した5バイトを解放したい。 解放したい場合はどうしたらいいんですか? char *str = "abcd"; printf("%x,%x,%x,%x,%x\n", str[0], str[1], str[2], str[3], str[4], str[5]); str = "de"; printf("%x,%x,%x,%x,%x\n", str[0], str[1], str[2], str[3], str[4], str[5]); 結果は 61, 62, 63, 64, 0 64, 65, 0, 25, 23 この時、str が確保しているのはまだ5バイトですか? char *str = "abcd"; の後に str = "de"; としました。 どこかのサイトで、ポインタの値を書き替えてはいけない と書いてあったのを見たような記憶があります。 この結果は企画にない結果だったんですか? char *str; で宣言したポインタに大きなサイズのデータを格納した場合、 プログラムが終了するまで、その大きなサイズを確保しているのは よくないことだから解放したいと思って質問しました。

その他の回答 (6)

  • superpaw7
  • ベストアンサー率40% (4/10)
回答No.7

> char *str[] = {0x61, 0x0, 0x64}; 失礼しました。私のタイプミスです(笑) ご指摘ありがとうございました。 *はいらないですね。 > char str[] = {0x61, 0x0, 0x64}; 回答はみなさんの答えで的を得ています。 質問者がの処理系が違っていた場合には記述の曖昧さで悩んでしまうと可哀想かなと思ったので補足をしてみました。余計でしたら申し訳ないです。 そういう自分が上記のようなタイプミスしているくらいですから、私自身もまだまだ甘いですね。ただのタイプミスといえど挙動はかなり違いますからね。

  • leaz024
  • ベストアンサー率75% (398/526)
回答No.6

No.5 の方が「処理系依存」のことについて触れられていますが、それについてちょっとアドバイスを。 >signed か unsigned は処理系次第ではなかったでしたっけ。 >4バイトというのと、スタックに確保されるというのも、処理系次第ですよね。  最適化するとレジスタを使ってしまったりする事も。 どちらも確かにその通りです。 でも A__ さんに理解して欲しいのは、 >char * 型は、文字列処理以外にも使用される、ということ >ポインタ変数と文字列アドレスの関係について という部分です。 (それを説明するには、どちらも十分な説明だったと思いますが。) また、私はこの質問を、ポインタ変数を文字列で初期化した場合の、メモリとの関係について尋ねられているものだと思いました。 だとすれば、 > char *str[] = {0x61, 0x0, 0x64}; これでは文字列は生成されませんので、注意が必要です。 この記述では、それぞれのデータをアドレスとするポインタの配列ができるだけです。もちろん操作すると大変危険です。

  • superpaw7
  • ベストアンサー率40% (4/10)
回答No.5

最近 C 言語をやっていないので懐かしいです。 char *str[] = {0x61, 0x0, 0x64}; なんていう宣言もありですね。 みなさんの回答でちょっと気になった点を。 (あくまで char型は「0~255の整数型」) signed か unsigned は処理系次第ではなかったでしたっけ。 (関数内で宣言された char * 型の str は、スタックメモリ上に確保されます。無論、確保されるサイズは4バイトです。) 4バイトというのと、スタックに確保されるというのも、処理系次第ですよね。 最適化するとレジスタを使ってしまったりする事も。 なんんだかややこしい話ですね・・・

  • haporun
  • ベストアンサー率40% (230/562)
回答No.4

おもしろい発想です。 C言語勉強し始めの頃は、こんな疑問に大いにぶつかってください。 今回は、皆様の言うとおり、はずれですが。 おまけ情報です。 char*はCスタイルの文字列と呼ばれますが、これは\0(0x00)までを文字範囲とする、という規定の基に、様々な操作がなされます。 確保した領域の中に\0が見つからなければ、文字列操作関数は、確保してある領域を超え、一般保護違反というエラーが発生する危険性を秘めます。 VBやJAVA、Perlの文字列は、\0で終わるという保証はなく、わざわざこの文字列は何文字あるという情報と一緒に、変数を管理します。 でも、これによって\0を途中に含む文字列が作れますし、確保した範囲を超えてアクセスする危険性も低くなります。 ポインタマニアの、はぽるんでした。

A__
質問者

お礼

ありがとうございます。

  • leaz024
  • ベストアンサー率75% (398/526)
回答No.3

# 何か、メモリとポインタ変数との間に、変な誤解を持たれているようですが・・・ 「文字列」というのは、確保されるものではありません。例えば、   char *str = "abcd"; とすると、コンパイルした時点で、プログラム内部のどこかに 0x61, 0x62, 0x63, 0x64, 0x00(全部で5バイト)が用意されます。(文字列の最後には、'\0'が付加されることをお忘れなく!) この「用意」というのは、「プログラム実行時にメモリを確保してデータが配置される」のではなく、「コンパイルされたプログラムに、その一部として既に存在している」ということです。 ソース名が hoge.c だとすれば、hoge.exe の中には、"abcd" が含まれているのです。 (つまり)文字列はプログラムの一部なので、プログラムがメモリ上にロードされた時点でアドレスが決定されます。"文字列" は、そのアドレスを持っています。 関数内で宣言された char * 型の str は、スタックメモリ上に確保されます。無論、確保されるサイズは4バイトです。 str = "abcd" となっているので、str の確保されている4バイトの領域に、"abcd" が存在するメモリのアドレスが代入されます。 プログラム実行時に行われるのは、たったこれだけです。 つまり、ポインタ変数 str と、"abcd" が存在するメモリの間には、そのアドレスを知っていること以外、何の関係もないのです。 alloc系関数を用いた動的メモリ確保の場合も同じです。 malloc は必要サイズのメモリを確保し、その先頭アドレスを返します。 →これをポインタ変数で受け取るのは、メモリにアクセスするのに必要だからであって、このポインタにメモリを割り当てるわけではありません。 次にこのメモリ領域を解放する場合、malloc が返したアドレスを使って、free が解放処理を行います。 →無論アドレスを受け取ったポインタ変数を解放するわけではありません。ポインタ変数を介して、確保したメモリのアドレスを free に知らせるだけです。 (ですので「ポインタを解放する」という表現は、明らかに正しくありません。) 話を質問に戻しますが、文字列 "abcd" が存在していた5バイトの領域が、勝手に使用されてしまうことはありません。 意図的に str[2] = 0 ('\0'であるべき) としても、その5バイトの領域の内容が 0x61, 0x62, 0x00, 0x63, 0x00 になるだけであって、解放とかそういう次元の話は、全く関係ありません。 表示した時に「ab」しか表示されないだけであって、   str[2] = 'Z'; とすれば、「abZd」が、いつでも必ず表示されます。

  • sssohei
  • ベストアンサー率33% (33/98)
回答No.2

> このポインタ str は解放する必要がない。 むしろ、解放したらまずいです。 たぶん。判断されたのは printfで表示しても abしか出なかったからだと思いますが、これは\0(0x00)がCに置ける文字列の終わりを示すコードになっているからです。 もし、確保されていなければ、str[3]のアクセス時に不正終了しかねません。「確保されていないメモリ」にアクセスするわけですから。

関連するQ&A

  • charポインタへの文字列による動的確保

    char *c=new char("abcd"); のようにして、cに"abcd"のポインタを代入しようとしたのですが、 error C2440: '初期化中' : 'const char [5]' から 'char' に変換できません。 と出てきてうまくいきません。 どの様にすれば、メモリ確保と同字に文字列で初期化できるのでしょうか?

  • C言語の型と配列

    char* str[10]={"a","b"}; char* str2="c"; としたときにstr=str2とすると 型が合わないといったエラーが出ます。 でもstrって結局はポインタの配列の先頭要素のアドレスですよね。 ポインタにポインタを入れているので通るのかなと思ったんですけど、 配列で宣言するとポインタにも型がつくのでしょうか? この例だと strは char * を10個持つ配列をさすポインタ  で、 str2はchar *をさすポインタ みたいなかんじです。 質問の意味がわかりにくいですが、ご指摘をいただければ補足しますので よろしくお願いします。

  • char型での演算子

    畏れ入ります。 X番目の文字を調べたいとき strにStringbufferで文字列が入っていた場合 if(str.charAt != "") とすることができません。 互換性のない型、と出てしまいます。 また、""を’’ とすると、「空の文字リテラルです」 と出てしまいます。 charが空であることを調べるのにはどうすればいいですか?

    • ベストアンサー
    • Java
  • C言語:小文字を大文字に変換する関数を作成

    C言語超初心者です。学校の課題で次のような問題が出されました。 ・問題・ 次に挙げる縛りに沿い、以下の関数とメイン関数を作り、処理結果を画面に作成しなさい。 char *tst(char *str) ・strの中の文字列も小文字を大文字に変換し、変換した文字列が格納されているchar *に返す。 ・引数strの中の文字列は受け取った状態で手を加えない。 ・関数内でmalloc関数を使用し、領域を確保して大文字に変換した文字列を格納しreturnでポインタを返す。 ・malloc関数を使用する。 ---------------------------------------------------------------------------------- 大文字に変換するには while(*str != '\0') { if(*str >= 'a' && *str <= 'z') { *str -= 'a'- 'A'; } ++str; } というのは分かったのですがここから何をすするか全く分かりません。初心者なのでなるべく分かりやすく教えてもらえると有難いです。 お願いします。

  • メモリの解放について

    文字列の左右のスペースを削除する関数を作っています。 そこで引数の文字列と同じ領域のメモリを確保し、そこで一時的にスペースを削除する作業をしています。 作業が終わったら、引数のポインタに文字列をコピーし、作業領域を解放したいと思っています。 しかし、確保した領域を解放しようとすると、「セグメンテーション違反」なるエラーが出て、解放できません。どなたか分かる方ご教授お願いします。 void trim(char *str) { int i; int len; char *tmp_p, *save_p; tmp_p = (char *)malloc(strlen(str) + 1); strcpy(tmp_p, str); save_p = tmp_p; len = strlen(tmp_p); // 後方スペース削除 // ポインタを最後まで進める for(i = 0; i < len - 1; i++) { tmp_p++; } // 文字だった場合'\0'でターミネート while(tmp_p != save_p) { if(!isspace(*tmp_p)) { tmp_p++; *tmp_p = '\0'; break; } tmp_p--; } // 前方スペース削除 // ポインタを最初に戻す tmp_p = save_p; // 文字が出てくるまでポインタを進める while(isspace(*tmp_p)) tmp_p++; strcpy(str, tmp_p); // free(tmp_p); // <- セグメンテーション違反 }

  • char型ポインタ

    よくプログラムで charポインタだけ指定して、 #include<stdio.h> int main(){ char* p; p = "abcdef"; printf("%s",p); return 0; } のようにしているのをみかけますが、 メモリーを確保していなくても問題ないのでしょうか? char* p; p = (char*)malloc(7); strcpy(p,"abcdef"); としたのと同じでしょうか?

  • CHAR型ポインタについて。

    CHAR型ポインタについて。 当方C言語初心者です。 ポインタと文字列の関係分からないことが出てきました。 参考にしている本があり、そのページに下記のソースで「const char *pc1」のポインタ変数を用意して、そこに直接文字列を代入しています。 本来、「char *pc1」はchar型のアドレスを格納するための変数のはずなのに、その変数に文字列を代入してることに疑問を感じました。 この記述の仕方は間違っていないのでしょうか?また、アドレスを格納するための変数「*pc1」に「abcdefg」の文字列はどのようにメモリ上で格納されているのでしょうか? 知ってどうなるの?みたいな質問かもしれませんが、ご教授いただけると幸いです。 #include <stdlib.h> #include <string.h> void func(void) { const char *pc1 = "abcdefg"; //←ココ char *pc2 = (char *)malloc( strlen(pc1) +1); if ( pc2 ) { strcpy( pc2, pc1 ); free( pc2 ); } }

  • char *name1[4] とchar name2[][4] の違いについて

    C言語のことで質問があります。 char *name1[4]は char *name1[4] = {"abcdefghi","jkl","l","mn"}; と宣言でき,ポインタを4つ確保した形となりました。 char name2[][4]は char name2[][4] = {"abc","def","ghi","jkl","mno","pqr","stu","vwx"}; と4文字以内の文字列を初期化した数だけ確保した形となりました。 この結果からchar *name1[4]の意味は,char name2[][4]ではなくchar name2[4][]に近いと思いました。 しかし,char name2[4][]ではポインタを4つ確保した事にはならないみたいでコンパイルが通りません。 *name1[4]では4つのポインタを確保できるのに~と思ってしまいます。 ポインタと配列は別物と考えるべきなのでしょうか? 訳の分からない質問かもしれませんが, 何卒ご指導いただくようよろしくお願いします。

  • (char*)について

    ソースを見ている際に、 以下のようなソースがありました。 構造体Aのメンバ char x char y[5+1] の2つがあり、 ある関数のなかで構造体Aのポインタを引数で渡しており、 それをマクロに対して、 (1)マクロB("あいうえお",(char*)A->x, sizeof(A->x,) ) (2)マクロB("かきくけこ",A->y sizeof(A->y) ) という風にわたしていました。 そこで質問なのですが、(1)に対してだけ第2引数に、(char*)が ついていますが、これはどういった意味があるのでしょうか?

  • c言語 型変換について

    c言語 型変換について 下記のように文字コードは、unsigned int型('B')をunsigned char 型(str[1] ) 格下げする型変換する規則を教えてください。 *質問ソースプログラム: int main(void) { char str[4]; /* 文字列を格納する配列 */ str[0] = 'A'; /* 代入 */ str[1] = 'B'; /* 代入 */ ・・・・・・ printf("size B %u\n",(unsigned)sizeof('B')); printf("size str[1] %u\n",(unsigned)sizeof(str[1])); * 実行結果 size B 4 size str[1] 1

専門家に質問してみよう