文字列とポインタ

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

文字列とポインタ

#1

投稿記事 by » 16年前

こんにちは。
c言語は初心者で、今テキストを見ながら進めています。
下記のプログラムは読み込んだ英文字以降の文字列を表示するプログラムです。
#include <stdio.h>

char *str_chr(const char *str, int c);

int main(void)
{
    char str[10], *p;
    char uletter[/url] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    printf("英大文字を入力してください:");
    scanf("%s", str);

    p = str_chr(uletter, str[0]);
    if (p != NULL) {
        puts(p);
    }

    return 0;
}

char *str_chr(const char *str, int c)
{
    for ( ; *str; str++) {
        if (*str == c) {
            return ((char *)str);
        }
    }

    return (NULL);
}
・for ( ; *str; str++)は想像的に文字列の先頭文字を走査していると(?)思うんですけど、
 これはfor (i = 0; *str != '\0'; i++) と解釈してもよろしいのでしょうか?でも、その場合
 だとint i;が宣言されていないですよね…?

・return ((char *)str);
これは一致した英大文字のアドレスを返すということなのでしょうか?
 また、その場合どうしてこのような式になるのでしょうか?

よろしければ、アドバイスをお願いします。

kazuoni

Re:文字列とポインタ

#2

投稿記事 by kazuoni » 16年前

>これはfor (i = 0; *str != '\0'; i++) と解釈してもよろしいのでしょうか?
インクリメントするっというところは同じですが、
何をインクリメントしているのかが違います。
iはint型、strはcharのポインタ型です。
str="ABC"だとしたら初めは'A'へのアドレスをstr_chrの第一引数に渡しますので、
str++は'B'へのアドレスになります。


>また、その場合どうしてこのような式になるのでしょうか?
キャストという用語を調べてみてください。
また、return strでコンパイルしてみると、どうなるか、一度試してみてください。

non

Re:文字列とポインタ

#3

投稿記事 by non » 16年前

>これはfor (i = 0; *str != '\0'; i++) と解釈してもよろしいのでしょうか?

ダメです。
参考までに。
char *str_chr(const char str[/url], int c)
{
	int i;
    for (i=0; str; i++) {
        if (str == c) {
            return ((char *)&str);
        }
    }

    return (NULL);
}

Re:文字列とポインタ

#4

投稿記事 by » 16年前

こんにちは、回答ありがとうございます。

キャストという用語を調べてみました。(型)式:式の値を型に変換するという意味ですね。

この場合、どうしてキャストをする必要があるのでしょうか?

御津凪

Re:文字列とポインタ

#5

投稿記事 by 御津凪 » 16年前

今回の場合だと、 const のついた型からついていない型にキャストしています。

この const とは、読み取り専用の型を示しています。
このとき、戻り値が char* 型に対し、返したい型の方は const char* ですので、
読み取り専用の型を読み書きできる型に変換するために、
このようなキャスト処理をしています。

Re:文字列とポインタ

#6

投稿記事 by » 16年前

>この const とは、読み取り専用の型を示しています。
>このとき、戻り値が char* 型に対し、返したい型の方は const char* ですので、
>読み取り専用の型を読み書きできる型に変換するために、
>このようなキャスト処理をしています。

・この読み取り専用の型(const)が、どうしてここで使われているのですか?
・返したい型はconst char*ですよね?でも、プログラムでは(char)になっています。

すいません、よかったら、もう少し詳しく説明を頂ければ嬉しいです。

Re:文字列とポインタ

#7

投稿記事 by » 16年前

すいません、訂正です。

・返したい型はconst char*ですよね?でも、プログラムでは(char *)strになっています。

御津凪

Re:文字列とポインタ

#8

投稿記事 by 御津凪 » 16年前

> ・この読み取り専用の型(const)が、どうしてここで使われているのですか?

読み取り専用の型の変数は、その変数を利用して値を変更することが出来ないという保障が原則としてついています。
関数の引数で const のポインタ型を使用することで、関数内でポインタで参照された値が変更されない
ということを保障していることになります。

str_chr は、指定した文字を探すだけで、値を変更する必要が無いので、 const が付いています。


> ・返したい型はconst char*ですよね?でも、プログラムでは(char *)strになっています。

関数の宣言は、
char *str_chr(const char *str, int c);
となっていて、戻り値の型は str_chr の前に記されています。
つまり、返したい(返される)型は char * です。

Re:文字列とポインタ

#9

投稿記事 by » 16年前

御津凧さん、ご回答丁寧にありがとうごさいました。

ちょっと、質問があるのですが、
下記のプログラムは文字列strの中に、文字cが含まれている個数調べるプログラムです。
#include <stdio.h>

int str_chnum(const char *str, int c)
{
	int count = 0;

	while (*str) {
		if (*str++ == c) {
			count++;
		}
	}
	return (count);
}

int main(void)
{
	char str[256];
	char ch[10];

	printf("文字列を入力してください:");
	scanf("%s", str);

	printf("検索する文字を入力してください:");
	scanf("%s", ch);

	printf("その文字は%d個含まれています。\n", str_chnum(str, ch[0]));

	return 0;
}
・この場合、return ((int)count)でも、実行できました。ということは、この場合は省略可能ということですよね?

・先ほどのプログラムだと、retun (str)で実行してみると、一応実行できたのですが、警告:問題のあるポインタ変換と表示されました。この場合、どうして(char *)を省略すると警告が表示されるのですか?

御津凪

Re:文字列とポインタ

#10

投稿記事 by 御津凪 » 16年前

> ・この場合、return ((int)count)でも、実行できました。ということは、この場合は省略可能ということですよね?

そうです。元々 count は int 型なので。
float 型や double 型の浮動小数点型から変換する場合等は、
警告を言われる場合がありますので、その時はキャストしたほうが良いです。


> 警告:問題のあるポインタ変換

上記に書いた場合もそうですが、警告なので、
コンパイラが判断した(暗黙的)キャストは行なっています(コンパイルされる)が、
これは意図したものですか?と注意を促しているものです。

return (str) での警告は、コンパイラが読み取り専用の型を勝手に読み書きできる型に変換しているため、
「問題のあるポインタ変換をしました」と、警告を表示しています。
このポインタ変換が問題ないのであれば、この警告を消すために、
return ((char *)str) と、(明示的)キャストを行なう必要があります。

Re:文字列とポインタ

#11

投稿記事 by » 16年前

御津凧さん、ご丁寧な回答ありがとうございます。

今までの文章を何度か読んでみたのですが、分かるような分からないような感じです。

p = str_chr(uletter, str[0]);
内のこの p の中にはstr_chr関数から返されるアドレスが格納されるのですよね?
たとえば、検索する文字 F を入力するとその値のアドレスがPに格納されるのですか?

御津凪

Re:文字列とポインタ

#12

投稿記事 by 御津凪 » 16年前

> たとえば、検索する文字 F を入力するとその値のアドレスがPに格納されるのですか?

P ではなく、 p ですね。
正確に言えば、検索する文字の位置を示すポインタが格納されます。

このとき、検索対象の文字列 str は、読み取り専用として関数に渡されます。
そして、戻り値はその str の中で見つけた文字の位置を示し、読み書き可能な型にキャストされて返されています。

単純にこの関数を使用した例を示すと、
int main( void ){
    char        str1[32] = "TEST TEXT.";  // 書き換え可能な文字列
    const char *str2     = "CONST TEXT."; // 読み取り専用の文字列

    char *ret;                // str_chr 関数からの戻り値を受け取る変数。

    ret = str_chr(str1,'.');  // str1 から '.' を検索。
    *ret = '!';               // 検索された文字を '!' に変更。
    printf("str1:%s\n",str1); // str1 を出力。"str1:TEST TEXT!"となる。

    ret = str_chr(str2,'.');  // str2 から '.' を検索。
    *ret = '?';               // 検索された文字を '?' に変更。
    printf("str2:%s\n",str2); // str2 を出力。"str2:CONST TEXT?"となる。

    return 0;
}
このようになります。
str2 は、読み取り専用で初期化されているはずなのに、変更できてしまっています。
つまり、今回のキャストの場合では、処理上は問題なくても、
読み書きできる型に変更したというだけの違いだけです。
なので、
const char *str_chr(const char *str, int c);
としても処理に問題はありませんが、上記のプログラムでは
読み取り専用型の値を読み書き可能型の値に代入しようとしているので、
コンパイルエラー(あるいは警告)になります。


# ちなみに、私は御津凪(みつなぎ)です。御津じゃないです。

Re:文字列とポインタ

#13

投稿記事 by » 16年前

大変、失礼致しました、御津凪さん。

あと、丁寧な回答ありがとうございました。

Re:文字列とポインタ

#14

投稿記事 by » 16年前

char *str_chr(const char *str, int c);

この関数名の前にどうして、*が付くのでしょうか?

Blue

Re:文字列とポインタ

#15

投稿記事 by Blue » 16年前

char型のポインタを戻り値にするから。

Re:文字列とポインタ

#16

投稿記事 by » 16年前

>char型のポインタを戻り値にするから。
回答ありがとうございました。基本的なこと忘れてました・・・

Mist

Re:文字列とポインタ

#17

投稿記事 by Mist » 16年前

関数名に*が付いているんじゃなくて、charに*が付いているんです。
だから本来は

char* str_chr(const char *str, int c);

なんです。

でも、ポインタの変数を宣言するときに

char *p;

と変数名のほうに*を付けて書きますよね。
それと同じように書いたために関数名のほうに*が付いているんです。

本来は以下のように書くべきなのですが、

char* p,q;

C言語の仕様のおかしなところでこう書くとpはchar型ポインタになりますが、qはただのchar型になってしまいます。
そのため、C言語プログラマは間違えないように変数のほうに*を付けるようになってしまったのです。

Re:文字列とポインタ

#18

投稿記事 by » 16年前

すいません、もう一つだけ。

p = str_chr(uletter, str[0]);

このポインタpにはstr_chr関数の中で一致した英大文字が指すアドレスが入るのですか?

御津凪

Re:文字列とポインタ

#19

投稿記事 by 御津凪 » 16年前

そうですよ。
(一致しなければ NULL が入りますが)

non

Re:文字列とポインタ

#20

投稿記事 by non » 16年前

>一致した英大文字が指すアドレスが入るのですか?

書き間違いだとは思いますが・・・
一致した英大文字が格納されている場所のアドレスが入るのです。

閉鎖

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