Подтвердить что ты не робот

Присвоение делает указатель из целого без приведения

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

Может кто-нибудь объяснить эти предупреждения?

4b9b3361

Ответ 1

Строки C не похожи на строки Java. Они суть массивы символов.

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

Ваш strToLower делает все изменения на своем месте, нет никаких оснований для его возврата, особенно не char. Вы должны "вернуть" void или char *.

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

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

Ответ 2

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

Ответ 3

Как уже отмечалось, в одном случае вы пытаетесь вернуть cString (который является значением char * в этом контексте - указателем) из функции, объявленной для возврата a char (которая является целое число). В другом случае вы делаете обратное: вы присваиваете возвращаемое значение char указателю char *. Это то, что вызывает предупреждения. Вам обязательно нужно объявить свои возвращаемые значения как char *, а не как char.

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

То, что я также хотел заметить, состоит в том, что в нескольких ответах вы можете заметить относительно странное предложение вернуть 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 * пригодится). Просто имейте в виду, что такие "цепные" вызовы функций иногда трудно отлаживать с пошаговым отладчиком.

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

Ответ 4

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

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

 

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

Ответ 5

Вам не нужны эти два параметра:

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

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

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

Ответ 6

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

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

Ответ 7

strToLower должен возвращать char * вместо char. Что-то подобное сделало бы.

char *strToLower(char *cString)

Ответ 8

char cString1[]

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

char strToLower(...)

Однако это возвращает char. Итак, ваше задание

cString1 = strToLower(cString1);

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

Решение состоит в том, чтобы сделать strToLower return char*.