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] 以降の領域は確保されていないから
後で、知らないうちに値が変わっている可能性がある。

という想像をしてみたけど、あってますか?

このQ&Aに関連する最新のQ&A

A 回答 (7件)

こんにちは、honiyonです。



 ハズレです。
 最初に 4byte確保したなら、str[2] = NULL; としても 4byte確保されています。
 char*型はあくまで「char型へのポインタ」であり、メモリの操作は行いません。

 0x00 も立派な「データ」ですよ。

 char* = 文字列データ という意味合いが強いですが、あくまで char型は「0~255の整数型」であり、それ以外の用途にも使用される事があります。 char* でメモリを確保し、バイナリデータを扱う事だって出来ます。

 参考になれば幸いです(..
    • good
    • 0
この回答へのお礼

ありがとうございます。
ハズレでしたか。

メモリの操作は行わないという意味が分かりませんでした。

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;
で宣言したポインタに大きなサイズのデータを格納した場合、
プログラムが終了するまで、その大きなサイズを確保しているのは
よくないことだから解放したいと思って質問しました。

お礼日時:2002/03/21 19:35

> char *str[] = {0x61, 0x0, 0x64};


失礼しました。私のタイプミスです(笑)
ご指摘ありがとうございました。
*はいらないですね。
> char str[] = {0x61, 0x0, 0x64};

回答はみなさんの答えで的を得ています。
質問者がの処理系が違っていた場合には記述の曖昧さで悩んでしまうと可哀想かなと思ったので補足をしてみました。余計でしたら申し訳ないです。
そういう自分が上記のようなタイプミスしているくらいですから、私自身もまだまだ甘いですね。ただのタイプミスといえど挙動はかなり違いますからね。
    • good
    • 0

No.5 の方が「処理系依存」のことについて触れられていますが、それについてちょっとアドバイスを。



>signed か unsigned は処理系次第ではなかったでしたっけ。
>4バイトというのと、スタックに確保されるというのも、処理系次第ですよね。
 最適化するとレジスタを使ってしまったりする事も。

どちらも確かにその通りです。
でも A__ さんに理解して欲しいのは、
>char * 型は、文字列処理以外にも使用される、ということ
>ポインタ変数と文字列アドレスの関係について
という部分です。
(それを説明するには、どちらも十分な説明だったと思いますが。)

また、私はこの質問を、ポインタ変数を文字列で初期化した場合の、メモリとの関係について尋ねられているものだと思いました。
だとすれば、
> char *str[] = {0x61, 0x0, 0x64};
これでは文字列は生成されませんので、注意が必要です。
この記述では、それぞれのデータをアドレスとするポインタの配列ができるだけです。もちろん操作すると大変危険です。
    • good
    • 0

最近 C 言語をやっていないので懐かしいです。


char *str[] = {0x61, 0x0, 0x64};
なんていう宣言もありですね。

みなさんの回答でちょっと気になった点を。

(あくまで char型は「0~255の整数型」)
signed か unsigned は処理系次第ではなかったでしたっけ。

(関数内で宣言された char * 型の str は、スタックメモリ上に確保されます。無論、確保されるサイズは4バイトです。)
4バイトというのと、スタックに確保されるというのも、処理系次第ですよね。
最適化するとレジスタを使ってしまったりする事も。

なんんだかややこしい話ですね・・・
    • good
    • 0

おもしろい発想です。


C言語勉強し始めの頃は、こんな疑問に大いにぶつかってください。
今回は、皆様の言うとおり、はずれですが。

おまけ情報です。
char*はCスタイルの文字列と呼ばれますが、これは\0(0x00)までを文字範囲とする、という規定の基に、様々な操作がなされます。
確保した領域の中に\0が見つからなければ、文字列操作関数は、確保してある領域を超え、一般保護違反というエラーが発生する危険性を秘めます。

VBやJAVA、Perlの文字列は、\0で終わるという保証はなく、わざわざこの文字列は何文字あるという情報と一緒に、変数を管理します。
でも、これによって\0を途中に含む文字列が作れますし、確保した範囲を超えてアクセスする危険性も低くなります。

ポインタマニアの、はぽるんでした。
    • good
    • 0
この回答へのお礼

ありがとうございます。

お礼日時:2002/07/14 09:17

# 何か、メモリとポインタ変数との間に、変な誤解を持たれているようですが・・・



「文字列」というのは、確保されるものではありません。例えば、
  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」が、いつでも必ず表示されます。
    • good
    • 0

> このポインタ str は解放する必要がない。


むしろ、解放したらまずいです。

たぶん。判断されたのは
printfで表示しても
abしか出なかったからだと思いますが、これは\0(0x00)がCに置ける文字列の終わりを示すコードになっているからです。

もし、確保されていなければ、str[3]のアクセス時に不正終了しかねません。「確保されていないメモリ」にアクセスするわけですから。
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q文字列がNULLか空文字列かの判定

Visual C++で、Cのプログラムを作成しているものです。(OS:WinNT 4.0)
文字列の扱いについて、質問します。

関数 int func(char *str) があると仮定します。
パラメータとして、strは以下のような状態あるとします。
(strは関数が呼ばれる前にcalloc()で領域確保済み)
 シンボル名 値
 str      0x00000001 ""
上記の状態で、strがNULLか空文字列("")であることを条件式にしたいのですが、str == NULL は偽となり、strcmp(str, "") を使用すると異常終了します。
どうしたらよいのでしょうか。アドバイスをお願いします。

Aベストアンサー

No1の方の回答にあるように、calloc()で取れた領域のアドレスを正しく渡せてないように思えますが...

#defineERROR(-1)

int func(char *str)
{
  if( (!str) || (!strlen(str)) ) return ERROR;
  return strlen(str);
}

void main()
{
  char *p=(char*)calloc(10,10);
  printf("%d\n",func(p));
}

Qchar*を初期化したいのですが

Cの標準関数だけで
char*を初期化したいのですが
どの様にすればいいのでしょうか?

char* a = "aaaa";
char* b = "bbbb";
strcat( a, b );//"aaaabbbb"?
とし使いまた後で
aにまた値を入れ直したいので
初期化して再利用したいのですが

どのようにすればいいのでしょうか?

ポインタとかもうっすら(ほとんどわかりません)
よろしくお願いいたします

Aベストアンサー

> char* a = "aaaa";
> char* b = "bbbb";
> strcat( a, b );//"aaaabbbb"?
この上のコードは間違っていますよ。
変数a、bに入っているのはあくまでも文字列の"ポインタ"です。
従いまして、strcat( a, b );とすると、aがさしているメモリは5バイトしかないのでメモリを破壊してしまいます。
static char sza[] = "aaaa";
static char szb[] = "bbbb";
char szBuffer[256];
char* a = szBuffer;
strcpy (a, sza);
strcat (a, szb);
としないとだめです。

またポインタ変数はNULLで初期化可能です。

Qc 文字列の終わりを示すコードは 0x00 それとも '?0' , '/0' ?

cの本を参考にプログラムをかじっているのですが、
本には '?0' と書いてあり、それで出力してみるとうまくいかず
いろいろインターネットで調べたのですが、
0x00 だとうまくいきました。
良くわからないのですが、なぜでしょう?

スミマセンおねがいします。

Aベストアンサー

文字列の最後には'\0'(NULL)が必要になります。
0x00で上手くいったのは、
NULLも「整数値の0」だからです。

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);

Qファイル出力の場所を指定

現在C++にてhtmlファイルを出力するプログラムを作っているのですが、出力場所を指定することはできるのでしょうか?(現在はそのプログラムソースが保存されている場所と同じファイル内に出力されますが、それをデスクトップに出力するなど。)
もし、方法がありましたら、教えてください。
ソースや参考HPのURLなどのせていただけたらありがたいです。
環境はVisualStudio.NET2003です。
よろしくお願いします。

Aベストアンサー

単にファイル名の前にパスを指定する。

絶対パス指定
fp=fopen("c:/temp/test.txt","w");

相対パス指定
fp=fopen("./hoge/test.txt","w");


デスクトップはOSやユーザによって場所が異なるので、少し面倒です。
XPの場合環境変数を利用してこんな感じで出来ると思います。

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

void main(void)
{
FILE *fp;
char fname[1024];
strcpy(fname,getenv("USERPROFILE"));
strcat(fname,"/デスクトップ/test.txt");
fp=fopen(fname,"w");
//処理
fclose(fp);
}

Qfgetsで拾われる改行文字を削除したい

お世話になります

 C言語初心者のものです。今課題でC言語を用いたプログラミングを
Fedora上でやっています。問題は、fgetsでテキストファイルから、取得
した文字列の中から改行文字を削除できないことです。文字変数のアド
レスはわかっているのですが、終端文字に置換しようとすると、セグメ
ントエラーになってしまいます。これは如何にして解決すべきでしょう
か。よろしくお願いします。

Aベストアンサー

ポインタとかアドレスとか、C言語の用語としてあるものを別の意味に使うとまぎらわしいです。

「ポインタ」「アドレス」と言われたら、 この例なら str, str+i が思い浮びます。
「文字変数のアドレス」だと
char c ;
に対しての
&c
が思い浮びます。

配列なら「添字」、意味的には「x文字目」ですね。

> for(i=0;;i++){
> if(*(str+i)=='/n') {
> *(str+i)='\0';
> break;
> }
> }
/nが\nの間違いなら、この方法で半分正解です。もう少し広い範囲(可能なら全体)で見ないことにはなんとも言えません。
fgetsが最大文字数に達したり、ファイルの最後になったりで、strに改行文字が含まれない場合には、このループは止まりません(Segmentension Falutになって止まる)

・そのような状態になってないか、予めチェックする
・ループを終了させる仕組みを用意しておく
: forの終了条件を記述する、for中で if(*(str+i)=='\0') { break;} 等としておく、等
といった対策が必要です。


あと細かいところを言えば
・strを配列で用意したなら *(s+i)じゃなくてs[i]でいいんじゃないかな
・あるいは char *pみたいにしておいて、 iのループでなく pでループを組む( for(p=str;*p!='\0';p++) )とか。

ポインタとかアドレスとか、C言語の用語としてあるものを別の意味に使うとまぎらわしいです。

「ポインタ」「アドレス」と言われたら、 この例なら str, str+i が思い浮びます。
「文字変数のアドレス」だと
char c ;
に対しての
&c
が思い浮びます。

配列なら「添字」、意味的には「x文字目」ですね。

> for(i=0;;i++){
> if(*(str+i)=='/n') {
> *(str+i)='\0';
> break;
> }
> }
/nが\nの間違いなら、この方法で半分正解です。もう少し広い範囲(可能なら全体)で見ないことにはなんとも言えません。
fgetsが...続きを読む

QCStringからchar*への型変換について教えてください。

以前の質問に

int型 → CString型/char型

がありましたが、

CString型をchar*型に変換する方法を
教えていただければありがたいです。

MSDNで「LPCTSTRキャスト」が説明されていましたが、
例が載ってないのでよくわかりませんでした。

よろしくお願いします。

Aベストアンサー

目的にもよりますが一時的にchar配列として使いたいならCString::GetBuffer()が利用できます。
char配列としての利用が終わったらCString::ReleaseBuffer()する必要がありますが。

直接CString内の文字列を扱う必要があるならCString::operator LPCTSTRで文字列ポインタが得られます。
ただし、CStringオブジェクトをいじると無効ポインタなる可能性があるので気をつけてください。

MSDNのMicrosoft Foundation Classリファレンス→CString→クラスメンバで確認してください。

Qchar型にint型の数値を代入する。

たとえば、
int num;
char box; 

numに何らかの整数値が入っているときに、そのnumの中に入っている値をchar型に文字列として代入したいときはどのようにすればいいのでしょうか?

Aベストアンサー

sprintf()っていう関数がありますよ。書式は

sprintf(char型の配列の先頭ポインタ,フォーマット,変数...)

二番目の引数以降はprintf()の引数と同じです。たとえば

int num;
char box[256];
num=100;
sprintf(box,"%d",num);
printf("%s",box);

→100と出力される

Q「memcpy」と「strcpy」について

C言語の初心者です。
先日、課題として以下のようなことを言われました。

「memcpyとstrcpyについて、メモリ破壊が起こるとしたら
どんな場合が考えられるか、簡単にまとめて報告してみて下さい。」
と言われました。

私にはメモリ破壊というニュアンスが分からないのですが、
どちらの関数も必要以上にコピーを行ったときに
起こるメモリ破壊ということなのでしょうか?
それとも、何か特別な意味があるのでしょうか?

C言語に詳しい方がいましたら、是非、教えて下さい。
宜しくお願いします。

Aベストアンサー

 メモリ破壊とは、「当然そこに入っているべき値」を、不用意に上書きしてしまうことです。

 たとえば、char a[100]; という宣言をしたとします。

 memcpy( a, 0, 200 );

 すると、このような実行を行った場合、変数 a の後ろにどんなメモリが存在しているのかプログラマは知ることができないのに、変数 a の後ろの未定メモリ100バイトを上書きしてしまいます。

 この未定メモリには、もしかしたら別の変数があるかもしれませんし、プログラムの一部があるかもしれません。あるいはOSのシステム領域かもしれません。
 どのみちプログラムは正常に動かなくなります。
 通常はメモリエラーが出て停止しますが、最悪の場合、メモリ上のOSを破壊してリセットするしかなくなったりもします。

 これがメモリ破壊です。

Qprintf による16進表示について

C言語初心者です。

今作っているプログラムで、データを16進形式で表示しようとしています。
大体このような感じです。

/*入力時*/
char buf[5]={0x4e,0x94,0xa0,0x2b,0x78}

/*出力時*/
for (i = 0; i < 5; i++) {
printf("0x%02x\n",buf[i])
}

実際には入力後にある処理によってbufは更新されるのですが、printfの出力結果として、

0xffffff4e
0x94
0xffffffa0
0x2b
0x78

というように、'ffffff'が付加したものがいくつか出力されてしまいます。
これはどういった意味を持つのでしょうか?

なんか初心者ならではの漠然とした質問ですいません。。。

Aベストアンサー

出力は、
0x4e
0xffffff94
0xffffffa0
0x2b
0x78
ではありませんか?
char が符号付(-128~127)のため、0x80~0xffは負の数とみなされます。printfの引数になる時に 符号付charは符号付intに変換されますが、このCコンパイラの場合は、int が4バイトcharが1バイトのため、上位3バイトに負の数を示すffffffが入ります。
char x=255;
printf("%d\n",x);
だと255でなく、-1が表示されます。

対応としては、
unsingned char buf[5]={0x4e,0x94,0xa0,0x2b,0x78}
;
とするか、
printf("0x%02x\n",buf[i]&0xff);
にするかどちらかですね。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング