ポインタ

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
あsdf

ポインタ

#1

投稿記事 by あsdf » 15年前

①のプログラムは正常に動作しますが、②のプログラムは、コンパイルはできるのですが、実行した際に強制終了されてしまいます。なぜでしょうか。

#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;
}

あsdf

Re:ポインタ

#2

投稿記事 by あsdf » 15年前

一応言っておきます。
①と②の違いは、char *a があるかないかというだけです。

OSは、windows7で、Borland C++ Compilerを使っています。

Dixq (管理人)

Re:ポインタ

#3

投稿記事 by Dixq (管理人) » 15年前

本当にコンパイル通りますか?
少なくとも<ctype.h>をインクルードする必要があるように思いますが。

後、

char *str;

ではアドレスの入れ物を用意しただけで文字列を入れるいれ物は用意されていません。
この場合、そのように用意するのではなく例えば

char str[20];

のように用意すれば20文字(19+ヌル文字)格納できる入れ物が用意できます。
今回うまくいったのはたまたまだと思います。

あsdf

Re:ポインタ

#4

投稿記事 by あsdf » 15年前

返信ありがとうございます。

コンパイルは、両方とも通ります。そして、①は正常に動作します。
しかし、この①も char *str の部分がおかしいとのことですが、何がおかしいかよく分かりません。

char str[20]; のように宣言すると、19個の文字までしか受け取れないので、20以上の文字数が打たれた際には要素数を超えてしまいますが、ポインタだと、任意の文字数を受け取れると思ったのですが・・・
(例えば、abcという文字が打たれたとすると、strのさすアドレスにa、次のアドレスにb・・・というふうになると思ったのですが、違うのでしょうか)

もしかして、char*型の変数は初期化を必ずしないといけないのでしょうか。
さっきためしに、char *str="";としてみたら、②の場合でも正常に動きました。

たかぎ

Re:ポインタ

#5

投稿記事 by たかぎ » 15年前

> 本当にコンパイル通りますか?
> 少なくとも<ctype.h>をインクルードする必要があるように思いますが。

それはC++の話では?
C、少なくともC90ではコンパイルできます。C99では未定義になりますが、普通はコンパイルできます。

私の手元の環境では、両方ともSegmentation faultになるので、動いているのはたまたまです。

Dixq (管理人)

Re:ポインタ

#6

投稿記事 by Dixq (管理人) » 15年前

じゃこんなたとえ話をしましょう。
今、下のように

「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の先頭アドレスを用意したらいいか解るでしょうか?

ということで、ポインタを用意しただけじゃダメなのです。

Dixq (管理人)

Re:ポインタ

#7

投稿記事 by Dixq (管理人) » 15年前

> たかぎさん

> それはC++の話では?

あ、そうだったのですね。C++でコンパイルしていました。
http://homepage1.nifty.com/MADIA/vc/C/c_lang_ansi12.htm
ここ見て必要なのかと思いました。
良く見たらvoid main・・・

愛用のボーヨーさんの所でも・・
http://www.bohyoh.com/CandCPP/C/Library/islower.html

たかぎ

Re:ポインタ

#8

投稿記事 by たかぎ » 15年前

islowerやtolowerなどを使う場合は、<ctype.h>をインクルードするのが筋ではあります。
ただ、行儀は悪くても<ctype.h>なしでコンパイルできますし、規格上も保証されます。

あsdf

Re:ポインタ

#9

投稿記事 by あsdf » 15年前

配列を使うことによりちゃんと動作しました。

ポインタについてもっと理解を深めようと思います。

ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る