割り当てはキャストせずに整数からポインタを作成します

2010-01-16 c warnings

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つの警告が生成されます。

  • 割り当てはキャストなしで整数からポインタを作成します
    • cString1 = strToLower(cString1);
    • cString2 = strToLower(cString2);
  • キャストなしでポインタから整数を返す
    • cStringを返します。

誰かがこれらの警告を説明できますか?

Answers

C文字列はJava文字列のようなものではありません。それらは基本的に文字の配列です。

strToLowerがcharを返すため、エラーが発生します。 charはCの整数の形式です。これをポインタであるchar []に割り当てています。したがって、「整数をポインタに変換する」。

strToLowerは、すべての変更を適切に行います。特にcharを返さない理由はありません。 voidまたはchar *を「返す」必要があります。

strToLowerの呼び出しでは、割り当ての必要もありません。cString1のメモリアドレスを渡すだけです。

私の経験では、Cの文字列は、Java / C#のバックグラウンドからCに戻る人にとって学ぶのが最も難しい部分です。Javaでも配列を割り当てることが多いので、人々はメモリ割り当てに慣れることができます。最終的な目標がCではなくC ++である場合は、C文字列に重点を置かず、基本を理解し、STLのC ++文字列を使用することをお勧めします。

strToLowerの戻り型はchar*ではなくchar char*必要があります (または文字列を再割り当てしないため、何も返さないはずです)

  • 1)しないで使用すると、 gets !バッファオーバーフローの脆弱性を導入しています。代わりにfgets(..., stdin)使用してください。

  • 2)ではstrToLowerあなたは戻っているcharの代わりに、 char -arrayを。 Autopulatedが提案するようにchar*を返すか、とにかく入力を変更しているため、単にvoid返しvoid 。結果として、

 strToLower(cString1);
 strToLower(cString2);
  • 3)大文字と小文字を区別しない文字列を比較するには、 strcasecmp (LinuxおよびMac)またはstricmp (Windows)を使用できます。

次の2つの割り当ては必要ありません。

cString1 = strToLower(cString1); 
cString2 = strToLower(cString2);

文字列を適切に変更します。

警告は、charを返し、char [](char *と同等)に割り当てているためです。

char cString1[]

これは配列です。つまり、同じデータ型の要素の範囲の最初の要素へのポインタです。配列を値渡しではなくポインタ渡しにしていることに注意してください。

char strToLower(...)

ただし、これはcharを返します。だからあなたの割り当て

cString1 = strToLower(cString1);

代入演算子の両側に異なる型があります。実際には、配列に 'char'(整数の一種)を割り当てています。これは、単純なポインタに解決されます。 C ++の暗黙の変換規則により、これは機能しますが、結果ごみであり、配列にさらにアクセスすると、未定義の動作が発生します。

解決策は、 strToLowerchar*返すようにすることstrToLower

配列の最初の文字へのポインタであるchar *ではなく、charを返します。

インプレース変更を行う代わりに新しい文字配列を返したい場合は、パラメーターとして割り当て済みのポインター(char *)または初期化されていないポインターを要求できます。この最後のケースでは、新しい文字列に適切な数の文字を割り当てる必要があり、Cパラメーターでは値によって常に渡されるので、関数によって内部的に割り当てられた配列の場合はパラメーターとしてchar **を使用する必要があることに注意してください。もちろん、呼び出し元は後でそのポインターを解放する必要があります。

strToLowerは、charではなくchar *を返す必要があります。このような何かがします。

char *strToLower(char *cString)

他の人がすでに述べたように、ある場合には、 char (整数)を返すように宣言された関数からcString (このコンテキストではchar *値-ポインタ)を返そうとしています。別のケースでは、逆を行いますchar戻り値をchar *ポインターに割り当てます。これが警告をトリガーするものです。あなたは確かにあなたのような戻り値を宣言する必要があるchar *ではないとして、 char

ところで、これらの割り当ては実際には言語の観点からの制約違反です (つまり、「エラー」です)。Cでポインターと整数を(整数定数ゼロを除いて)混在させることは違法であるためです。コンパイラは、この点に関して寛容すぎて、これらの違反を単なる「警告」として報告します。

また、文字列をインプレースで変更しているため、関数からvoidを返すという比較的奇妙な提案に気付くかもしれません。これは確かに機能しますが(実際に文字列をインプレースで変更しているため)、関数から同じ値を返すことには何の問題もありません。実際、これは、C言語ではかなり標準的な方法です( strcpyなどの標準関数を参照してください)。これは、使用することを選択した場合に関数呼び出しの「連鎖」を可能にし、 「チェーン」を使用しないでください。

とはcompareStringcompareString実装での割り当ては、完全に不必要に見えます(何も壊されませんが)。それらを取り除くか

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 *リターンが便利になるときです)。このような「連鎖された」関数呼び出しは、ステップバイステップのデバッガーでデバッグするのが難しい場合があることに注意してください。

追加の非現実的な注記として、このような破壊的な方法で文字列比較関数を実装する(入力文字列を変更する )のは最善のアイデアではないかもしれません。非破壊的な機能は私の意見でははるかに価値があります。入力文字列を小文字に明示的に変換する代わりに、通常、文字ごとに大文字と小文字を区別しないカスタム文字列比較関数を実装し、標準のstrcmpを呼び出す代わりにそれを使用することをおstrcmpます。

Related