ソースコード1
void str_up(char *str)
{
int i=0;
while(str!=NULL){
if('A'<=*str && *str<='Z'){
*str=*str+32;
}
str=str+1;
}
}
ソースコード2
void str_up(char *str)
{
int i = 0;
while (str[i] != '\0')
{
if ('A' <= str[i] && str[i] <= 'Z')
{
str[i] = str[i] + 32;
}
i++;
}
}
大文字を小文字に変換するプログラムを作ろうと思い、ソースコード1を作ってみたのですが期待通りに動かず、ソースコード2を作ってみたら期待通りに動きました。ソースコード1もソースコード2もやっていることは同じだと思うのですが、ソースコード1がなぜ動かなかったのかがわからないままです。原因わかる方いたら教えてほしいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
ベストアンサー
[前提知識1]
Cでは文字列というプリミティブな型はなく、文字型の配列に順次文字を格納し、最後に文字列の終了のマーク(終端文字)として'\0'つまり値0を配置することで文字列を表すということにしています。
[前提知識2]
NULLは、ポインタがどこも指していないことを示す特別な値です。ただ、その特別な値としてなにか具体的なものが必要ですから、0を割り当てています。実はアドレス0というのは存在するのですが、C言語で直接アクセスすることはそうそうは無いでしょう、という割り切り。また、ポインタが何も指していないときにNULLにするのは自動(言語の機能)ではなく、プログラマが意図して設定してやる必要があります。
つまり、str!=NULL
は「ポインタが有効(どこかを指しているか)を調べる」ことであって、「文字列の終わり」を検出することではありません。ここの間違いが前者のプログラムが動かない原因です。
実際の動作を考えるのなら、
void str_up(char *str)
と宣言された関数を、有効なポインタを引数に与えて呼び出したならstrは有効なポインタです。str=str+1;
としている限りは、strは有効なポインタでありつづけるでしょう。つまり、str!=NULL
は常に真になってしまいます(strが変数としてオーバーフローすると0つまりNULLになりますが...)。
言語規則の範囲内で見ればそういうことなのですがしかし、プログラムが動作するのは現実のコンピュータ上です。ちゃんとしたOS上で動くプログラムであれば、OSからあるメモリを割り当てられて、その範囲内で動かなければなりません。割り当てられたメモリ範囲を逸脱してアクセスしようとすると、OSによって強制終了させられてしまうことになるでしょう。
なお、*str != NULL
と記述するとプログラムは「動いてしまう」でしょう。Cは型の違いに鷹揚なのでNULL(void*型の0)を'\0'整数値の0に勝手に変換して比較を行ってしまいますから(警告ぐらいは出るかも)。動きはしますがしかし「意味」としては異常なことをやっているわけで、やってはいけません。
もう一ついうと、Cでは言語として文字コードを規定していません。そして、'A'~'Z'あるいは'a'~'z'の文字コードが連続していることは保証しません('0'~'9'が連続していることは規定されています)。
質問のプログラムは、'A'~'Z', 'a'~'z'が連続していて、'A'と'a'のオフセットが0x20であるという(C言語には決められていない)前提を要求していることは意識しましょう(asciiコード)。現在の世の中のコンピュータの多くはその要求を満たしているとは思いますが、全てではありませんので。
投稿2021/01/03 00:22
編集2021/01/03 09:22総合スコア7703
0
while(str!=NULL)
「str が NULL でない間~」であり「str の指す値が 0 でない間~」ではないから。
while ( *str != '\0' ) とでも書けばよかった。
投稿2021/01/02 12:35
編集2021/01/02 12:36総合スコア16612
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
'A'~'Z'あるいは'a'~'z'の文字コードが連続していることは保証されていないときの処理を書いてあげたらととコメントしたら戻ってきてしまいました。tolowerを使うのは気が引けるので、それを使わない移植性のあるプログラムを載せておきます。
行数は多いですが、初期化は一回しか走らないので、比較しながら置き換えるよりは速いかもしれません。
C
1#include <stdio.h> 2#include <string.h> 3 4static char up2lowtable[128] = 5 {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 6 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, 7 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, 8 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, 9 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, 10 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, 11 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, 12 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}; 13static int initialized = 0; 14 15static void initialize(void) { 16 up2lowtable['A'] = 'a'; 17 up2lowtable['B'] = 'b'; 18 up2lowtable['C'] = 'c'; 19 up2lowtable['D'] = 'd'; 20 up2lowtable['E'] = 'e'; 21 up2lowtable['F'] = 'f'; 22 up2lowtable['G'] = 'g'; 23 up2lowtable['H'] = 'h'; 24 up2lowtable['I'] = 'i'; 25 up2lowtable['J'] = 'j'; 26 up2lowtable['K'] = 'k'; 27 up2lowtable['L'] = 'l'; 28 up2lowtable['M'] = 'm'; 29 up2lowtable['N'] = 'n'; 30 up2lowtable['O'] = 'o'; 31 up2lowtable['P'] = 'p'; 32 up2lowtable['Q'] = 'q'; 33 up2lowtable['R'] = 'r'; 34 up2lowtable['S'] = 's'; 35 up2lowtable['T'] = 't'; 36 up2lowtable['U'] = 'u'; 37 up2lowtable['V'] = 'v'; 38 up2lowtable['W'] = 'w'; 39 up2lowtable['X'] = 'x'; 40 up2lowtable['Y'] = 'y'; 41 up2lowtable['Z'] = 'z'; 42 initialized = 1; 43}; 44 45char *up2low(char *str) { 46 int i; 47 int n = strlen(str); 48 if (initialized == 0) initialize(); 49 for (i=0; i<n; i++) { 50 str[i] = up2lowtable[str[i]]; 51 } 52 return str; 53} 54 55void main(int argc, char *argv[]) { 56 printf("%s\n", up2low(argv[1])); 57} 58
実行結果は以下です。
shell
1$ ./up2low aAbBXY1Z%9+@ 2aabbxy1z%9+@
投稿2021/01/03 12:10
総合スコア24670
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/01/03 01:08
2021/01/03 02:20
2021/01/03 02:27
2021/01/03 02:58
2021/01/03 07:45
2021/01/03 08:21 編集
2021/01/03 08:39
2021/01/03 09:20
2021/01/03 11:11
2021/01/03 11:24
2021/01/03 11:28
2021/01/03 12:11
2021/01/04 23:58
2021/01/05 00:30 編集
2021/01/05 03:50
2021/01/05 04:14 編集
2021/01/05 04:36
2021/01/05 05:11 編集
2021/01/05 06:21
2021/01/05 06:23
2021/01/05 06:25
2021/01/05 07:02
2021/01/05 07:10
2021/01/05 07:14
2021/01/05 07:18
2021/01/05 07:42
2021/01/05 07:47 編集
2021/01/05 07:55
2021/01/05 09:03
2021/01/05 09:07
2021/01/05 10:17
2021/01/05 10:29
2021/01/05 10:35 編集
2021/01/05 10:35
2021/01/05 10:42 編集