Назначение делает указатель из целого числа без приведения - PullRequest
23 голосов
/ 15 января 2010

Исходя из фона 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 ]

37 голосов
/ 15 января 2010

C-строки не похожи на строки Java. По сути, это массивы символов.

Вы получаете ошибку, потому что strToLower возвращает символ. Char - это форма целого числа в C. Вы назначаете его в char [], который является указателем. Отсюда "преобразование целого числа в указатель".

Ваш strToLower вносит все свои изменения на месте, у него нет причин возвращать что-либо, особенно не символ. Вам следует «вернуть» void или символ *.

При вызове strToLower также нет необходимости в присваивании, вы просто передаете адрес памяти для cString1.

По моему опыту, строки в C - самая сложная часть для изучения всем, кто возвращается с фона Java / C # обратно в C. Люди могут справиться с распределением памяти (поскольку даже в Java вы часто выделяете массивы). Если ваша конечная цель - C ++, а не C, вы можете меньше сосредоточиться на строках C, убедиться, что вы понимаете основы, и просто использовать строку C ++ из STL.

5 голосов
/ 15 января 2010

тип возвращаемого значения strToLower должен быть char*, а не char (или он вообще ничего не должен возвращать, так как не перераспределяет строку)

2 голосов
/ 15 января 2010

Как уже отмечали другие, в одном случае вы пытаетесь вернуть cString (в данном контексте значение char * - указатель) из функции, которая объявлена ​​для возврата char (которая является целое число). В другом случае вы делаете обратное: вы присваиваете char возвращаемое значение указателю char *. Это то, что вызывает предупреждения. Вам, безусловно, нужно объявить возвращаемые значения как char *, а не 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 * возврат пригодится). Просто помните, что такие «цепочечные» вызовы функций иногда сложно отладить с помощью пошагового отладчика.

В качестве дополнительной, нереализованной заметки я бы сказал, что реализация функции сравнения строк таким деструктивным способом (она изменяет входные строки) может быть не самой лучшей идеей. Неразрушающая функция имела бы гораздо большую ценность, по моему мнению. Вместо того, чтобы выполнять явное преобразование входных строк в нижний регистр, обычно лучше реализовать собственную функцию сравнения строк без учета регистра символов и использовать ее вместо вызова стандартного strcmp. * 1031. *

1 голос
/ 15 января 2010
  • 1) Не используйте gets!Вы вводите уязвимость переполнения буфера.Вместо этого используйте fgets(..., stdin).

  • 2) В strToLower вы возвращаете char вместо char -массива.Либо верните char*, как предложил Autopulated, либо просто верните void, так как вы все равно изменяете ввод.В результате просто напишите

 strToLower(cString1);
 strToLower(cString2);
  • 3) Для сравнения строк без учета регистра вы можете использовать strcasecmp (Linux & Mac)или stricmp (Windows).
0 голосов
/ 15 января 2010

strToLower должен возвращать символ * вместо символа. Нечто подобное может подойти.

char *strToLower(char *cString)
0 голосов
/ 15 января 2010

Вы возвращаете char, а не char *, который является указателем на первый символ массива.

Если вы хотите вернуть новый массив символов вместо того, чтобы выполнять модификацию на месте, вы можете запросить уже выделенный указатель (char *) в качестве параметра или неинициализированный указатель. В этом последнем случае вы должны выделить надлежащее количество символов для новой строки и помнить, что в параметрах C передается значение ALWAYS, поэтому вы должны использовать char ** в качестве параметра в случае массива, выделенного внутри функцией. Конечно, вызывающая сторона должна освободить этот указатель позже.

0 голосов
/ 15 января 2010
char cString1[]

Это массив, т. Е. Указатель на первый элемент диапазона элементов одного типа данных.Обратите внимание, что вы передаете не массив по значению, а по указателю.

char strToLower(...)

Однако это возвращает символ.Таким образом, ваше присваивание

cString1 = strToLower(cString1);

имеет разные типы на каждой стороне оператора присваивания. Вы фактически присваиваете массиву (тип целого числа), который разрешается простым указателем.Из-за неявных правил преобразования C ++ это работает, но результат - это мусор, и дальнейший доступ к массиву вызывает неопределенное поведение.

Решение состоит в том, чтобы strToLower вернуть char*.

0 голосов
/ 15 января 2010

Вам не нужны эти два задания:

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

вы изменяете строки на месте.

Предупреждения вызваны тем, что вы возвращаете char и присваиваете ему char [] (что эквивалентно char *)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...