C言語関係掲示板

過去ログ

No.136.toupper関数を使って、文字列を変換


No.865

torpper関数を使って、文字列を変換したいのですが...
投稿者---めい助(2002/01/17 23:39:07)


初めて投稿させていただきます、めい助と申します。
さっそくですが、以下に示しますソースプログラムが、LSI-Cのコンパイラ
ではエラーも出ずコンパイル出来るのですが、思うような結果にならず悶々と
悩んでいます。

#include<stdio.h>
#include<ctype.h>

void string_up(char *ch);

int main(void)
{
char *str = "abcd";
string_up(str);

return 0;
}

void string_up(char *ch)
{
while(*ch)
*ch++ = torpper(*ch);

printf("%s", ch);
}

本当は、"ABCD" と返してくれるのを期待したのですが、何も表示されないまま終了してしまいます。 ちなみに、関数 string_up の printf 文の部分を main 関数の方へ記述するとうまく行くのですが、何故そうなるのかわからなくて悩んでいます。 すいませんが、よきアドバイスを頂けますでしょうか?




No.867

Re:torpper関数を使って、文字列を変換したいのですが...
投稿者---ともじ(2002/01/18 00:09:37)


こんばんは。

>本当は、"ABCD" と返してくれるのを期待したのですが、何も表示されないまま終了してしまいます。 ちなみに、関数 string_up の printf 文の部分を main 関数の方へ記述するとうまく行くのですが、何故そうなるのかわからなくて悩んでいます。 すいませんが、よきアドバイスを頂けますでしょうか?
>

torpperではなくtoupperですよね。

それから、string_up関数の中で、
	while(*ch)
	*ch++ = toupper(*ch);   

してポインタchを更新しているのに、
	printf("%s", ch);

NUL文字を指しているアドレスでprintfしているので
何も出力されないのです。




No.875

Re:ともじさん! kikkさん! ありがとうございました!!!
投稿者---めい助(2002/01/18 21:31:58)


>torpperではなくtoupperですよね。

すいませんでした(^^; こんな所で間違えるなんて(笑)...

>それから、string_up関数の中で、
>NUL文字を指しているアドレスでprintfしているので
>何も出力されないのです。

言われて初めてわかりました。考えてみれば実に当たり前の事なんですが、自分
が正しい! と思っている内は、こんなミスにも気がつかないんですね(笑)。

それから、kikk さん! 文字列リテラル処理の件、アドバイス頂きまして
ありがとうございました。
実は、こちらのホームページで 10-3 文字列とポインター の所をしっかり
プリンターで印刷していたのにも関わらず、完璧に見落としていました...

スペルを間違い、NULL文字を指し、リテラルを変更しようとして...
これじゃあ動くものも動かないですよね(爆)?

これからも、こちらのホームページをどんどん活用させて頂こうと思ってい
ます。 また、とんでもない質問(?)をさせていただくかも知れませんけど
宜しくお付き合い下さいませ...



No.871

ちょっと補足(文字列リテラルへの書き込み)
投稿者---kikk(2002/01/18 11:07:01)


ども。


うまくいかない原因とは(今回は)関係ありませんが。

文字列リテラル(文字列定数)は、処理系によっては書き込み禁止領域に確保
される可能性があります。今回のプログラムでは、文字列リテラルへの書き
込みを行っているため、処理系およびOSによってはうまくいかない(実行時に
落ちる)ことがあります。

(今回のプログラムで)これを回避するには

> char *str = "abcd";



/* *strで文字列リテラル"abcd"を指すのではなく、str[]にコピー */
char str[] = "abcd";

に変えればOKです。上の2つの式の違いはポインタと文字列と配列について
調べてみてください(というか、コメントの通り)。


では。

No.872

Re:ちょっと補足(文字列リテラルへの書き込み)
投稿者---ともじ(2002/01/18 17:35:48)


kikkさん、いつも補足ありがとうございます。

>文字列リテラル(文字列定数)は、処理系によっては書き込み禁止領域に確保
>される可能性があります。

見落としていました。確かに文字列リテラルを書き換えていますね。
文字列リテラルについては
http://www9.plala.or.jp/sgwr-t/sec10-3.htm#s10-3-mr
にもまとめてありますのでご参考になさってください。

No.873

Re:ちょっと補足(文字列リテラルへの書き込み)
投稿者---akira(2002/01/18 19:43:57)


こんにちは。 いつも活用させて頂いてます。

>>文字列リテラル(文字列定数)は、処理系によっては書き込み禁止領域に確保
>>される可能性があります。
>
>見落としていました。確かに文字列リテラルを書き換えていますね。
>文字列リテラルについては
>http://www9.plala.or.jp/sgwr-t/sec10-3.htm#s10-3-mr
>にもまとめてありますのでご参考になさってください。

上記に関して少し質問させて下さい。
char *str;
str=strtok(line,",");
とした時の str も文字列リテラルと同じ扱いなのでしょうか?
あまり変更を加えるのはよろしくない?
実はこのstrに関して変更を加えたくて色々調べてたところです。
strを配列へコピーしたいとは思ったんですけど、力不足です…
strを直接変更・配列などにして(出来るのでしょうか?)変更、
どちらでも構いませんのでアドバイス頂ければありがたいです。


No.874

Re:ちょっと補足(文字列リテラルへの書き込み)
投稿者---組み込み初心者(2002/01/18 21:08:08)


>上記に関して少し質問させて下さい。
>char *str;
>str=strtok(line,",");
>とした時の str も文字列リテラルと同じ扱いなのでしょうか?
>実はこのstrに関して変更を加えたくて色々調べてたところです。

strtokの実装を想像してみるに、変更すること自体は問題ないように思います。
でも次回strtokを呼び出したときに違う文字列に書き換わる可能性があるので、
strcpy(copy_str, str);
などとしてcopy_strをいじったほうがいいと思います。


No.876

Re:ちょっと補足(文字列リテラルへの書き込み)
投稿者---B.Smith(2002/01/18 22:17:57)


以下の説明は、関数strtokの大まかな処理内容です。
この原理から、ポインタの意味を知ることができますが、世の中すべてのstrtokが同じ処理をしているとは限らないので注意してください。この説明が適しているかは、戻されたポインタが、元のバッファの範囲を指すか、と言う簡単な検査で分かります(ちなみにMicrosoftは問題ありません)。

関数strtokは、内部で切り出し文字(2番目の引数で指定した文字)を発見したらヌルに置き換える、という処理を行います。
char    Str[] = "*.ASM;*.C;*.CPP;*.H";
char    *tk;

tk = strtok(Str,";");

検索開始位置を保存しておき、区切り文字を検索します。区切り文字を発見したら、それをヌルに置き換え、検索開始位置を戻り値として返します。
開始位置
   ↓
   * . A S M \0 * . C ; * . C P P ; * . H
             ↑
       最初の区切り文字
   strtokがヌルに置き換える

次の検索位置は関数内部の静的領域に保存されます。2回目以降の切り出しでは、1番目の引数をNULLにすることで、保存された位置から切り出しを続行します。
          次の検索開始位置
      (静的領域に保存される)
                ↓
   * . A S M \0 * . C ; * . C P P ; * . H
             ↑
       最初の区切り文字

これらの操作は1番目の引数で与えられたバッファ内で行われます。このため、1番目の引数に与えるバッファは書き込み可能なものでなければなりません。文字列定数を与えた場合は、まず正常に動作しないと思った方が良いです(実際にはコンパイラに依存するため、正常に動作する場合もあります)。
別の見方をするならば、戻されたポインタは書き込み可能なバッファを指しているはずなので、バッファの中身を変更することも可能です
2番目の引数、区切り文字を指定するバッファは、内部で参照しているだけなので、文字列定数でも問題ありません。



No.886

Re:ちょっと補足(文字列リテラルへの書き込み)
投稿者---組み込み初心者(2002/01/19 04:24:44)


> 1番目の引数に与えるバッファは書き込み可能なものでなければなりません
てっきりconstだと思ってました。
だから静的領域へのポインタを返すものだとばかり。
どうも、勉強なりました。


No.889

Re:ちょっと補足(文字列リテラルへの書き込み)
投稿者---akira(2002/01/19 15:26:35)


組み込み初心者さん、B.Smithさん
ありがとうございました。勉強になりました。
何とか処理してみます。

>> 1番目の引数に与えるバッファは書き込み可能なものでなければなりません
>てっきりconstだと思ってました。
>だから静的領域へのポインタを返すものだとばかり。
>どうも、勉強なりました。