Javaバックグラウンドから来ていますが、私はCを学習していますが、これらの曖昧なコンパイラーのエラーメッセージはますますイライラしています。私のコードは次のとおりです。
/*
* PURPOSE
* Do case-insensetive string comparison.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int compareString(char cString1[], char cString2[]);
char strToLower(char cString[]);
int main() {
// Declarations
char cString1[50], cString2[50];
int isEqual;
// Input
puts("Enter string 1: ");
gets(cString1);
puts("Enter string 2: ");
gets(cString2);
// Call
isEqual = compareString(cString1, cString2);
if (isEqual == 0)
printf("Equal!\n");
else
printf("Not equal!\n");
return 0;
}
// WATCH OUT
// This method *will* modify its input arrays.
int compareString(char cString1[], char cString2[]) {
// To lowercase
cString1 = strToLower(cString1);
cString2 = strToLower(cString2);
// Do regular strcmp
return strcmp(cString1, cString2);
}
// WATCH OUT
// This method *will* modify its input arrays.
char strToLower(char cString[]) {
// Declarations
int iTeller;
for (iTeller = 0; cString[iTeller] != '\0'; iTeller++)
cString[iTeller] = (char)tolower(cString[iTeller]);
return cString;
}
これにより、2つの警告が生成されます。
誰かがこれらの警告を説明できますか?
C文字列は、Java文字列のようなものではありません。本質的に文字の配列です。
StrToLowerが文字を返すため、エラーが発生します。 charはCの整数の形式です。ポインタであるchar []に割り当てています。したがって、「整数からポインターへの変換」。
StrToLowerはすべての変更をその場で行います。特にcharではなく、何かを返す理由はありません。 voidまたはchar *を「返す」必要があります。
StrToLowerの呼び出しでは、割り当ての必要もありません。基本的にcString1のメモリアドレスを渡すだけです。
私の経験では、Cの文字列は、Java/C#バックグラウンドからCに戻ってくる人にとって学ぶのが最も難しい部分です。人々はメモリの割り当てに慣れることができます(Java )。最終的な目標がCではなくC++である場合は、C文字列にあまり注意を向けず、基本を理解し、STLのC++文字列を使用することをお勧めします。
strToLowerの戻り値の型はchar*
not char
(または、文字列を再割り当てしないため、何も返さないはずです)
他の人が既に指摘したように、ある場合には、cString
(を返すように宣言された関数からchar
(このコンテキストではchar *
値-ポインター)を返そうとしています。これは整数です)。別のケースでは、逆の操作を行います。char
戻り値をchar *
ポインターに割り当てます。これが警告をトリガーします。戻り値をchar
ではなくchar *
として宣言する必要があります。
ところで、これらの割り当ては実際には言語の観点から制約違反(つまり、「エラー」)であることに注意してください。ゼロ)。あなたのコンパイラは、この点に関して単純に寛容すぎており、これらの違反を単なる「警告」として報告しています。
また、いくつかの答えでは、文字列をインプレースで変更しているため、関数からvoid
を返すという比較的奇妙な提案に気付くかもしれないということです。確かに機能しますが(実際に文字列をその場で変更しているので)、関数から同じ値を返すことは本当に悪いことではありません。実際、C言語では、使用することを選択した場合に関数呼び出しの「連鎖」を可能にし、コストがかかるため、該当する場合はstrcpy
などの標準関数を見てください。 「連鎖」を使用しない場合、実質的には何もありません。
そうは言っても、compareString
の実装内の割り当ては、完全に余分なものに見えます(それらが何も壊さないとしても)。私はそれらを取り除くか
int compareString(char cString1[], char cString2[]) {
// To lowercase
strToLower(cString1);
strToLower(cString2);
// Do regular strcmp
return strcmp(cString1, cString2);
}
または「連鎖」を使用して
int compareString(char cString1[], char cString2[]) {
return strcmp(strToLower(cString1), strToLower(cString2));
}
(これはchar *
のリターンが便利になるときです)。このような「連鎖」関数呼び出しは、ステップバイステップデバッガーではデバッグが難しい場合があることに注意してください。
追加の非現実的なメモとして、このような破壊的な方法で文字列比較関数を実装すること(つまりmodifies入力文字列)は、最良のアイデアではないかもしれません。私の意見では、非破壊機能ははるかに価値があります。入力文字列を小文字に明示的に変換する代わりに、通常、大文字と小文字を区別しないカスタム文字列比較関数を実装し、標準のstrcmp
を呼び出す代わりに使用することをお勧めします。
1)gets
を使用しないでください!バッファオーバーフローの脆弱性を導入しています。代わりにfgets(..., stdin)
を使用してください。
2)strToLower
では、char
- arrayではなく、char
を返します。 char*
Autopulatedが示唆したように、またはとにかく入力を変更しているので、単にvoid
を返します。結果として、ただ書く
strToLower(cString1);
strToLower(cString2);
strcasecmp
(LinuxおよびMac)またはstricmp
(Windows)を使用できます。次の2つの割り当ては必要ありません。
cString1 = strToLower(cString1);
cString2 = strToLower(cString2);
所定の場所で文字列を変更します。
警告は、charを返し、char [](char *と同等)に割り当てているためです。
配列の最初の文字へのポインタであるchar *ではなく、charを返しています。
インプレース変更を行う代わりに新しい文字配列を返したい場合は、パラメータとして割り当て済みのポインタ(char *)または初期化されていないポインタを要求できます。この最後のケースでは、新しい文字列に適切な数の文字を割り当てる必要があります。Cパラメーターでは、常に値によって渡されるため、関数によって内部的に割り当てられた配列の場合はchar **をパラメーターとして使用する必要があります。もちろん、呼び出し元は後でそのポインターを解放する必要があります。
strToLowerは、charではなくchar *を返す必要があります。このような何かがするだろう。
char *strToLower(char *cString)