ページ 1 / 1
ポインタ
Posted: 2010年5月15日(土) 02:34
by あsdf
①のプログラムは正常に動作しますが、②のプログラムは、コンパイルはできるのですが、実行した際に強制終了されてしまいます。なぜでしょうか。
①
#include <stdio.h>
#include <string.h>
void swapcase(char *s1) {
while (*s1) {
if (islower(*s1) != 0)
*s1 = toupper(*s1);
else
*s1 = tolower(*s1);
s1++;
}
}
int main(void) {
char *str;
printf("単語を入力(大文字小文字変換をする)");
scanf("%s", str);
if (strcmp(str, "quit") == 0)
return 0;
swapcase(str);
printf("%s\n", str);
return 0;
}
②
#include <stdio.h>
#include <string.h>
void swapcase(char *s1) {
while (*s1) {
if (islower(*s1) != 0)
*s1 = toupper(*s1);
else
*s1 = tolower(*s1);
s1++;
}
}
int main(void) {
char *str;
char *a;
printf("単語を入力(大文字小文字変換をする)");
scanf("%s", str);
if (strcmp(str, "quit") == 0)
return 0;
swapcase(str);
printf("%s\n", str);
return 0;
}
Re:ポインタ
Posted: 2010年5月15日(土) 02:37
by あsdf
一応言っておきます。
①と②の違いは、char *a があるかないかというだけです。
OSは、windows7で、Borland C++ Compilerを使っています。
Re:ポインタ
Posted: 2010年5月15日(土) 02:45
by Dixq (管理人)
本当にコンパイル通りますか?
少なくとも<ctype.h>をインクルードする必要があるように思いますが。
後、
char *str;
ではアドレスの入れ物を用意しただけで文字列を入れるいれ物は用意されていません。
この場合、そのように用意するのではなく例えば
char str[20];
のように用意すれば20文字(19+ヌル文字)格納できる入れ物が用意できます。
今回うまくいったのはたまたまだと思います。
Re:ポインタ
Posted: 2010年5月15日(土) 03:21
by あsdf
返信ありがとうございます。
コンパイルは、両方とも通ります。そして、①は正常に動作します。
しかし、この①も char *str の部分がおかしいとのことですが、何がおかしいかよく分かりません。
char str[20]; のように宣言すると、19個の文字までしか受け取れないので、20以上の文字数が打たれた際には要素数を超えてしまいますが、ポインタだと、任意の文字数を受け取れると思ったのですが・・・
(例えば、abcという文字が打たれたとすると、strのさすアドレスにa、次のアドレスにb・・・というふうになると思ったのですが、違うのでしょうか)
もしかして、char*型の変数は初期化を必ずしないといけないのでしょうか。
さっきためしに、char *str="";としてみたら、②の場合でも正常に動きました。
Re:ポインタ
Posted: 2010年5月15日(土) 03:33
by たかぎ
> 本当にコンパイル通りますか?
> 少なくとも<ctype.h>をインクルードする必要があるように思いますが。
それはC++の話では?
C、少なくともC90ではコンパイルできます。C99では未定義になりますが、普通はコンパイルできます。
私の手元の環境では、両方ともSegmentation faultになるので、動いているのはたまたまです。
Re:ポインタ
Posted: 2010年5月15日(土) 03:42
by Dixq (管理人)
じゃこんなたとえ話をしましょう。
今、下のように
「a100番地には4つの箱」
「a101番地には3つの箱」
「a102番地には5つの箱」
が用意されています。
a100 : □□□□
a101 : □□□
a102 : □□□□□
こんな感じですね。
プログラムコードで書けば
char a100[4];
char a101[3];
char a102[5];
と言ったところでしょうか。
今、100番地にある箱に"abc"を入れたとすると
a100 : a b c □
a101 : □□□
a102 : □□□□□
こんな感じになりますよね。(ヌル文字省略)
所で、
char *str;
は何を指すでしょうか?
これはポインタといって「アドレスを入れる入れ物」です。
先ほどの箱はデータそのもの、つまり文字を入れる事が出来たのに対して、これは「住所番号」を入れるものです。
他のものは入りません。
つまり、先ほどで言う「a100番地」とか「a101番地」というデータです。
その為、strにa100番地というデータを入れるとstrは「abc」を指します。
この事をプログラムで確認してみましょう。
#include <stdio.h>
int main(void) {
char a100[5]="abc";
char *str;
str = a100;
printf("%s",str);
return 0;
}
実行する前に何が出力されるか想像出来ますか?
ということで、
char *str;
ではデータを入れるための領域は確保されていません。
char a100[5];
とかけば5バイトのものが入れられる入れ物が用意されます。
文字列を入れたいなら必要なバイト数先に確保しなくてはなりません。
後、(1)は正常に動くと言っていらっしゃいますが、上でも書いたようにたまたま動いているだけで、間違っています。
他のPCでは動かないかもしれません。現に私のPCでは動きません。
>20以上の文字数が打たれた際には要素数を超えてしまいますが、ポインタだと、任意の文字数を受け取れると思ったのですが・・・
残念ながらそこまで融通は利きません。
プログラムはやれと言った事しかやってくれないので、自分で何文字入ってくるのか考えてその分先に確保しなければなりません。
>例えば、abcという文字が打たれたとすると、strのさすアドレスにa、次のアドレスにb・・・というふうになると思ったのですが、違うのでしょうか
ではstrの指すアドレスにaは無事格納出来たとしましょう。
次のアドレスにbと書いてありますが、そのアドレスが使用可能であるかはどうしてわかりますか?
ひょっとしたら100万文字入ってくるかもしれないんですよね。
コンパイラはPCのメモリのどこにstrの先頭アドレスを用意したらいいか解るでしょうか?
ということで、ポインタを用意しただけじゃダメなのです。
Re:ポインタ
Posted: 2010年5月15日(土) 03:45
by Dixq (管理人)
Re:ポインタ
Posted: 2010年5月15日(土) 04:24
by たかぎ
islowerやtolowerなどを使う場合は、<ctype.h>をインクルードするのが筋ではあります。
ただ、行儀は悪くても<ctype.h>なしでコンパイルできますし、規格上も保証されます。
Re:ポインタ
Posted: 2010年5月16日(日) 00:12
by あsdf
配列を使うことによりちゃんと動作しました。
ポインタについてもっと理解を深めようと思います。
ありがとうございました。