赋值使得整型指针没有强制转换
来自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);
- 返回从指针没有转换的整数
- 返回cString;
有人可以解释这些警告吗?
Cstring不像Javastring。 他们基本上是字符数组。
你正在得到错误,因为strToLower返回一个字符。 char是C中的一个整数forms。将它分配给一个char [],它是一个指针。 因此“将整数转换为指针”。
你的strToLower做了所有的改变,没有理由返回任何东西,特别是不是字符。 你应该“返回”无效或char *。
在调用strToLower时,也不需要赋值,实际上只是传递了cString1的内存地址。
根据我的经验,C语言中的Strings是学习任何来自Java / C#背景C的人最难的部分。人们可以与内存分配相处(因为即使在Java中你也经常分配数组)。 如果你的最终目标是C ++而不是C,那么你可能更less关注Cstring,确保你理解了基础知识,而只是使用STL中的C ++string。
strToLower的返回types应该是char*
不是char
(或者它根本不应该返回任何东西,因为它不会重新分配string)
-
1)不要使用
gets
! 您正在引入缓冲区溢出漏洞。 改用fgets(..., stdin)
。 -
2)在
strToLower
你正在返回一个char
而不是一个char
arrays。 要么返回char*
作为Autopulatedbuild议,要么只是返回void
因为无论如何你正在修改input。 因此,只写
strToLower(cString1); strToLower(cString2);
- 3)要比较不区分大小写的string,可以使用
strcasecmp
(Linux&Mac)或stricmp
(Windows)。
正如其他人已经指出的那样,在一种情况下,您试图从被声明为返回一个char
(这是一个整数)的函数返回cString
(在这个上下文中是一个char *
值 – 一个指针)。 在另一种情况下,你可以做相反的事情:你将一个char
返回值赋给一个char *
指针。 这是触发警告的原因。 你当然需要声明你的返回值为char *
,而不是char
。
注意,从语言的angular度来看,这些赋值事实上是约束违反 (即它们是“错误”),因为混合C中的指针和整数(除了整数常量零)是非法的。 你的编译器在这方面太简单了,把这些违规报告为“警告”。
我也想注意的是,在几个答案中,你可能会注意到相对奇怪的build议,从你的函数返回void
,因为你正在修改string就地。 虽然它肯定会起作用(因为你确实是在就地修改string),从函数返回相同的值没有任何问题。 实际上,在适用的情况下,这是一个相当标准的C语言实践(看一下像strcpy
和其他标准函数),因为如果你select使用函数调用,它可以“链接”函数调用,如果你不要使用“链接”。
也就是说,在你的compareString
实现中的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 *
返回将派上用场)。 请记住,这样的“链接”函数调用有时难以用分步debugging器进行debugging。
作为一个额外的,未经实践的说明,我会说,以这种破坏性的方式(它修改inputstring)实现string比较函数可能不是最好的主意。 一个非破坏性的function在我看来会更有价值。 除了将inputstring显式转换为小写外,通常更好的办法是实现一个自定义逐个字符的不区分大小写的string比较函数,并使用它来代替调用标准的strcmp
。
你不需要这两个分配:
cString1 = strToLower(cString1); cString2 = strToLower(cString2);
你正在修改string。
警告是因为你正在返回一个字符,并分配给一个char [](这相当于char *)
您正在返回字符,而不是char *,这是指向数组的第一个字符的指针。
如果你想返回一个新的字符数组而不是原地修改,你可以要求一个已经分配的指针(char *)作为参数或一个未初始化的指针。 在最后一种情况下,您必须为新string分配适当数量的字符,并记住在通过值ALWAYS传递的C参数中,因此必须在由函数内部分配数组的情况下使用char **作为参数。 当然,调用者必须稍后释放该指针。
strToLower应该返回一个char *而不是char。 像这样的事情会做。
char *strToLower(char *cString)
char cString1[]
这是一个数组,即指向同一数据types的一系列元素的第一个元素的指针。 请注意,您不是按值传递数组,而是按指针传递数组。
char strToLower(...)
但是,这返回一个字符。 所以你的任务
cString1 = strToLower(cString1);
在赋值运算符的每一边有不同的types..实际上,将一个“char”(整数types)赋值给一个数组,这可以parsing为一个简单的指针。 由于C ++的隐式转换规则,这是有效的,但结果是垃圾,进一步访问数组会导致未定义的行为。
解决办法是让strToLower
返回char*
。