コードには多くの問題があります。
char* s1 = "Bob";
char
文字列リテラルは;の読み取り専用配列を作成します。この配列は静的であり、プログラムの存続期間全体にわたって存在することを意味します。歴史的な理由から、これはconst
ではないため、変更しようとしてもコンパイラは必ずしも警告を表示しませんが、慎重に変更を避ける必要があります。
s1
その配列の最初の文字を指します。を変更することはできません*s1
。const
安全のために、ポインタを次のように宣言する必要があります。
const char *s1 = "Bob";
変更可能な文字配列が必要な場合は、次のように作成できます。
char s1[] = "Bob";
残りのコードを見てみましょう。
if (*s1 >= 97 && *s1 <= 122)
*s1 -= 32;
}
97
とはと122
の数値 ASCII コードです。は、小文字と対応する大文字の違いです -- 繰り返しますが、ASCII です。'a'
'z'
32
C 言語は、文字が ASCII で表現されること、またはそれと互換性のある文字セットで表現されることを保証しません。たとえば、IBM メインフレームでは、文字は EBCDIC で表されます。この場合、文字のコードは連続しておらず (ギャップがあります)、対応する小文字と大文字の違いは 32 ではなく 64 です。
最近では EBCDIC システムはまれですが、それでも移植可能なコードは移植不可能なコードよりも明確である傾向があり、コードがすべてのシステムで機能するかどうかという実際的な問題は別としても同様です。
ご存じのとおり、これを行う最善の方法は次のtolower
関数を使用することです。
*s1 = tolower((unsigned char)*s1);
へのキャストに注意してくださいunsigned char
。で宣言されたto*()
andis*()
関数は、<ctype.h>
歴史的な理由から奇妙な振る舞いをしています。char
それらは引数では機能しません。むしろ、int
の範囲内にある引数で動作しますunsigned char
。EOF
(通常は であるも受け入れ-1
ます)。プレーンchar
が署名されているchar
場合、たまたま負の値を渡すと、未定義の動作が発生します。はい、それは迷惑です。
しかし、あなたは使いたくないと言いますtolower
。(これは問題ありません。このようなことを自分で行うことを学ぶことは、良い練習になります。)
大文字が連続しており、小文字が連続していると仮定したい場合は、次のようにすることができます。
if (*s1 >= 'a' && *s1 <= 'z') {
*s1 -= 'a' - 'A';
}
これはまだ非 ASCII システムには移植できませんが、たまたま ASCII テーブルを記憶していなければ、読みやすくなります。
また、ロジックが逆になっていることが少し明らかになります。小文字に変換したいと言いますが、コードは小文字から大文字に変換されます。
または、小文字を大文字にマップするルックアップ テーブルを使用できます。
char to_lower[CHAR_MAX] = { 0 }; /* sets all elements to 0 */
to_lower['A'] = 'a';
to_lower['B'] = 'b';
/* ... */
to_lower['Z'] = 'z';
または、コンパイラが複合リテラルをサポートしている場合:
const char to_lower[CHAR_MAX] = {
['A'] = 'a',
['B'] = 'b',
/* ... */
};
残りはあなたに任せて、それを使用するコードを書きます。
tolower
これで、 関数と関数が存在する理由がわかりました。toupper
したがって、これらすべてのものを処理する必要はありません (必要になる奇妙なunsigned char
キャストは別として)。
アップデート :
あなたの質問の新しい部分に応えて:
char* temp = malloc(100);
temp = s1;
その割り当てtemp = s1;
は、割り当てられた文字列をコピーしません。ポインタをコピーするだけです。temp
割り当てられたスペースの 100 バイトを指しますがtemp
、(読み取り専用) 文字列リテラルを指すようにすると、割り当てられたスペースへの参照が失われ、メモリ リークが発生します。
C では文字列または配列を割り当てることはできません。文字列をコピーするには、次のstrcpy()
関数を使用します。
char *temp = malloc(100);
if (temp == NULL) { /* Don't assume the allocation was successful! */
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(temp, s1);
また、すでにメモリ内にある文字列にメモリを割り当てる必要があるのはなぜですか?
それはメモリ内にありますが、変更が許可されていないのはメモリです。変更する場合は、変更可能な場所にコピーする必要があります。または、上で提案したように、最初に読み取り/書き込みメモリに配置できます。
char s[] = "Bob";
その初期化により、文字列が配列にコピーされますs
。