Как убрать пару вещей:
НИКОГДА НИКОГДА НЕ НИКОГДА использовать gets()
; это будет вводить точку отказа в вашей программе. Если вы передадите, получите буфер размером 10 символов, и пользователь введет 100 символов, gets()
с радостью запишет эти дополнительные 90 символов в память сразу после вашего буфера, что приведет к всевозможным хаосам. Переполнения буфера - это простое и распространенное вредоносное средство, и любой код, использующий gets()
, небезопасен по конструкции . Вместо этого используйте fgets()
.
Вы не можете назначать объекты массива, как вы делаете в строке sReverse = reverse(sPhrase);
. Если вы хотите скопировать содержимое строки, возвращаемой reverse
, вам необходимо использовать strcpy()
или аналогичный: strcpy(sReverse, reverse(sPhrase));
Диагностика "несовместимые типы в назначении" основана на том факте, что вы пытаетесь присвоить значение указателя (char *
) объекту массива (char [STRMAX]
). Как я упоминал выше, вы все равно не можете назначить объект массива.
Предупреждение «Передача аргумента из несовместимого типа» происходит из-за того, что определение вашей функции типизировано не для ожидания указателя на символ, а для указателя на указатель на символ. Измените определение функции на
char *reverse(char *sPhrase) {...}
Почему *sPhrase
вместо sPhrase[]
(или *sPhrase[]
)? Прежде всего, когда выражение массива появляется в большинстве контекстов, его тип неявно преобразуется из «массива N-элементов T» в «указатель на T» (выражение распадается в тип указателя) и его значение устанавливается по адресу первого элемента в массиве; Исключениями из этого правила являются случаи, когда выражение массива является операндом операторов sizeof
или &
(address-of), или если выражение массива является строковым литералом, используемым для инициализации массива char в объявлении. , Во-вторых, в контексте определения параметра функции T a[]
идентичен T *a
; обе формы объявляют a
как указатель на T.
Когда вы вызываете reverse(sPPhrase);
в main
, тип выражения sPPhrase
затухает от «массива STRMAX-элемента char» до «указателя на char», поэтому необходимо ввести формальный параметр в функции как char *
.
Вы все равно можете применить оператор индексации к sPhrase, поскольку подписка определяется в терминах арифметики указателей, но помните, что sPhrase - это значение pointer , а не массив.
Как вы сейчас написали, reverse
ожидает параметр типа char *[]
, который идентичен char **
, как если бы вы передавали массив указателей на char, а не массив char. Аналогично, ваша переменная sOutput
в reverse
должна быть объявлена char sOutput[STRMAX];
, а не char *sOutput[STRMAX];
(последняя объявляет sOutput как массив указателей на char, что здесь не то, что вам нужно; это источник предупреждение "возврат из несовместимых типов").
Предупреждение "адрес возврата локальной переменной" происходит из-за того, что вы пытаетесь вернуть адрес переменной, которая является локальной для функции и имеет автоматический экстент. После выхода из функции эта переменная больше не существует, и значение, хранящееся в этом месте, может перестать быть действительным. Есть несколько способов обойти это:
Объявите sOutput как статический: static char sOutput[STRMAX];
. Это приведет к тому, что память для sOutput будет выделена при запуске программы и останется выделенной до выхода из программы, поэтому содержимое массива будет сохраняться между вызовами reverse
. Переменная все еще является локальной для функции (к ней нельзя обратиться по имени вне этой функции). Однако это означает, что функция больше не является поточно-ориентированной, и это уродливое решение.
Динамически выделить буфер в reverse
и вернуть адрес этого. Преимущество этого состоит в том, что вы можете изменять размер буфера по мере необходимости, и вам не нужно беспокоиться о безопасности потоков. Буфер будет сохраняться до тех пор, пока вы явно не освободите его (или пока программа не закроется). Недостаток заключается в том, что вызывающая сторона теперь отвечает за освобождение этой памяти, когда она закончена. Лучший способ избежать головной боли с управлением памятью - это, во-первых, избегать управления памятью, и эта проблема на самом деле не требует этого.
Выполните обратную операцию на месте (то есть сделайте обратную операцию во входном массиве) и верните адрес входного массива. Это означает, что вы вводите данные в заблуждение, что может быть не тем, что вы хотите.
Передайте массив назначения как второй вход функции и не беспокойтесь о возвращаемом значении (или, если у вас есть , чтобы вернуть что-то, верните адрес массива назначения) :
char *reverse(char *src, char *dst)
{
// write contents of src in reverse order to dst
return dst;
}
...
reverse(sPPhrase, sPReverse);
Так работают такие функции, как strcpy()
, поэтому есть прецедент для этого, и это наименее болезненный из всех вариантов.
Просто помните, что обработка строк в C является очень примитивом (здесь мы говорим о каменных ножах и медвежьих шкурах) и множеством концепций, которые имеют смысл в других языках (например, использование =
для назначения содержимое строки) не применяется в C.