赋值使得整数指针不需要强制转换

时间:2010-01-15 18:59:07

标签: 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;
}

这会产生两个警告。

  • 赋值从整数中生成指针而不进行强制转换
    • cString1 = strToLower(cString1);
    • cString2 = strToLower(cString2);
  • return在没有强制转换的情况下从指针生成整数
    • return cString;

有人可以解释这些警告吗?

8 个答案:

答案 0 :(得分:37)

C字符串与Java字符串不同。它们本质上是字符数组。

您收到错误是因为strToLower返回了一个char。 char是C中的整数形式。您将它分配给char [],它是一个指针。因此“将整数转换为指针”。

你的strToLower完成了所有的更改,没有理由返回任何内容,特别是不是char。你应该“返回”void或char *。

在调用strToLower时,也不需要赋值,你实际上只是传递cString1的内存地址。

根据我的经验,对于任何来自Java / C#背景的人来说,C语言中的字符串是最难学习的。人们可以与内存分配相处(因为即使在Java中,您也经常分配数组)。如果你的最终目标是C ++而不是C,你可能更愿意关注C字符串,确保你理解基础知识,并且只使用STL的C ++字符串。

答案 1 :(得分:5)

strToLower的返回类型应为char*而不是char (或者它应该什么都不返回,因为它没有重新分配字符串)

答案 2 :(得分:2)

正如其他人已经注意到的那样,在一种情况下,您试图从声明返回{{1}的函数返回cString(此上下文中的char *值 - 指针) (这是一个整数)。在另一种情况下,您可以反过来:您正在为char指针分配char返回值。这就是触发警告的原因。您当然需要将返回值声明为char *,而不是char *

请注意,从语言的角度来看,这些赋值实际上是约束违规(即它们是“错误”),因为在C中混合使用指针和整数是非法的(除此之外)从积分常数零)。你的编译器在这方面过于宽容,并将这些违规行为仅仅作为“警告”。

我还想注意的是,在几个答案中,您可能会注意到从函数返回char这一相对奇怪的建议,因为您正在修改字符串。虽然它肯定会起作用(因为你确实在原地修改字符串),但从函数返回相同的值并没有什么错。实际上,在C语言中它是一个相当标准的实践(适用于void等标准函数),因为如果您选择使用函数调用,它可以实现“链接”功能调用,以及成本如果你不使用“链接”,几乎没有。

也就是说,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-by-char不区分大小写的字符串比较函数,并使用它而不是调用标准char *

答案 3 :(得分:1)

  • 1)不要使用gets!您正在引入缓冲区溢出漏洞。请改用fgets(..., stdin)

  • 2)在strToLower中,您要返回char而不是char - 数组。要么将char*作为Autopulated建议返回,要么只返回void,因为您仍在修改输入。结果,只需写下

 strToLower(cString1);
 strToLower(cString2);
  • 3)要比较不区分大小写的字符串,您可以使用strcasecmp(Linux&amp; Mac)或stricmp(Windows)。

答案 4 :(得分:0)

您不需要这两个分配:

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

您正在修改字符串。

警告是因为你返回一个char,并指定一个char [](相当于char *)

答案 5 :(得分:0)

您正在返回char,而不是char *,它是指向数组第一个字符的指针。

如果要返回新的字符数组而不是进行就地修改,可以要求已经分配的指针(char *)作为参数或未初始化的指针。在最后一种情况下,您必须为新字符串分配适当数量的字符,并记住在CALL参数中由值ALWAYS传递,因此在函数内部分配的数组的情况下,必须使用char **作为参数。当然,调用者必须在以后释放该指针。

答案 6 :(得分:0)

strToLower应该返回char *而不是char。这样的事情就可以了。

char *strToLower(char *cString)

答案 7 :(得分:-1)

char cString1[]

这是一个数组,即指向同一数据类型的一系列元素的第一个元素的指针。请注意,您没有通过值传递数组,而是按指针传递。

char strToLower(...)

然而,这会返回一个char。所以你的作业

cString1 = strToLower(cString1);

在赋值运算符的每一侧都有不同的类型..你实际上是为一个数组分配一个'char'(整数),它解析为一个简单的指针。由于C ++的隐式转换规则可行,但结果垃圾,并且对数组的进一步访问会导致未定义的行为。

解决方案是让strToLower返回char*