Я пытаюсь вернуть строку C из функции, но она не работает. Вот мой код.
char myFunction()
{
return "My String";
}
В main
Я зову это следующим образом :
int main()
{
printf("%s", myFunction());
}
Я также пробовал другие способы myFunction
, но они не работают. Например:
char myFunction()
{
char array[] = "my string";
return array;
}
Примечание: мне не разрешено использовать указатели!
Небольшая справка по этой проблеме:
Есть функция, которая определяет, какой сейчас месяц. Например, если он равен 1, он возвращает январь и т. Д.
Поэтому , когда он собирается печатать, он делает это так: printf("Month: %s",calculateMonth(month));
. Теперь проблема в том, как вернуть эту строку из calculateMonth
функции.
return 0
по умолчанию подразумевается только в C99 (и C ++), но не в C90.Ответы:
Ваша подпись функции должна быть:
Задний план:
Это фундаментально для C и C ++, но мы не будем останавливаться на достигнутом.
В C (и C ++, если на то пошло) строка - это просто массив байтов, оканчивающийся нулевым байтом, поэтому термин «строка-ноль» используется для представления этого конкретного вида строки. Существуют и другие типы строк, но в C (и C ++) эта разновидность по сути понимается самим языком. Другие языки (Java, Pascal и т. Д.) Используют разные методологии для понимания «моей строки».
Если вы когда-либо использовали Windows API (который находится на C ++), вы довольно часто будете видеть параметры функции, такие как: «LPCSTR lpszName». Часть 'sz' представляет понятие 'нулевая строка': массив байтов с нулевым (/ нулевым) ограничителем.
Уточнение:
Ради этого «вступления» я использую слова «байты» и «символы» как синонимы, потому что так легче выучить. Имейте в виду, что существуют другие методы ( расширенные символы и многобайтовые системы символов ( mbcs )), которые используются для работы с международными символами. UTF-8 представляет собой пример MBCS. Ради вступления я все это незаметно «пропускаю».
Объем памяти:
Это означает, что строка типа «моя строка» фактически использует 9 + 1 (= 10!) Байтов. Это важно знать, когда вы наконец дойдете до динамического распределения строк.
Итак, без этого «завершающего нуля» у вас не будет строки. В памяти находится массив символов (также называемый буфером).
Долговечность данных:
Использование функции таким образом:
... как правило, приводит к случайным необработанным исключениям / ошибкам сегментов и т.п., особенно «в будущем».
Короче говоря, хотя мой ответ правильный - в 9 случаях из 10 вы получите программу, которая дает сбой, если вы используете ее таким образом, особенно если вы считаете, что это «хорошая практика». Вкратце: обычно это не так.
Например, представьте, что когда-нибудь в будущем строку нужно будет каким-то образом изменить. Как правило, программист выбирает легкий путь и (пытается) писать такой код:
То есть ваша программа выйдет из строя, потому что компилятор (может / не мог) освободил память, используемую к
szBuffer
моменту вызоваprintf()
inmain()
. (Ваш компилятор также должен заранее предупредить вас о таких проблемах.)Есть два способа вернуть строки, которые не так быстро прерываются.
std::string
) для обработки долговечности данных (что требует изменения возвращаемого значения функции), илиОбратите внимание, что невозможно использовать строки без указателей в C. Как я показал, они синонимы. Даже в C ++ с шаблонными классами всегда есть буферы (то есть указатели), используемые в фоновом режиме.
Итак, чтобы лучше ответить на (теперь измененный вопрос). (Наверняка будет множество «других ответов», которые могут быть предоставлены.)
Более безопасные ответы:
Пример 1 с использованием статически выделенных строк:
Что делает здесь «статика» (многим программистам не нравится этот тип «распределения»), так это то, что строки помещаются в сегмент данных программы. То есть он размещен постоянно.
Если вы перейдете на C ++, вы будете использовать аналогичные стратегии:
... но, вероятно, проще использовать вспомогательные классы, например
std::string
, если вы пишете код для собственного использования (а не как часть библиотеки для совместного использования с другими).Пример 2 с использованием буферов, определяемых вызывающим абонентом:
Это более надежный способ передачи строк. Возвращенные данные не подлежат манипуляции со стороны вызывающей стороны. То есть вызывающая сторона может легко злоупотребить примером 1 и подвергнуть вас ошибкам приложения. Таким образом, это намного безопаснее (хотя и требует большего количества строк кода):
Есть много причин, по которым второй метод лучше, особенно если вы пишете библиотеку для использования другими (вам не нужно блокировать конкретную схему распределения / освобождения, третьи стороны не могут взломать ваш код, и вам не нужно связываться с конкретной библиотекой управления памятью), но, как и весь код, вам решать, что вам больше всего нравится. По этой причине большинство людей выбирают пример 1, пока их не сожгут столько раз, что они отказываются писать его таким образом;)
Отказ от ответственности:
Я ушел на пенсию несколько лет назад, и теперь мой C немного заржавел. Этот демонстрационный код должен правильно компилироваться с C (хотя это нормально для любого компилятора C ++).
источник
char *
, поскольку строковые литералы в C имеют типchar[]
. Однако их нельзя изменять каким-либо образом, поэтомуconst char*
предпочтение отдается возврату (см. Securecoding.cert.org/confluence/x/mwAV ). Возвратchar *
может потребоваться, если строка будет использоваться в устаревшей или внешней библиотечной функции, которая (к сожалению) ожидаетchar*
аргумент as, даже если она будет только читать из него. C ++, с другой стороны, имеет строковые литералыconst char[]
типа (и, начиная с C ++ 11, вы также можете иметьstd::string
литералы).fraught with problems
в разделе «Долговечность данных», на самом деле совершенно действителен. Строковые литералы имеют статическое время жизни в C / C ++. См. Ссылку, упомянутую Георгием выше.Строка AC определяется как указатель на массив символов.
Если у вас не может быть указателей, по определению у вас не может быть строк.
источник
void foo( char array[], int length)
. Конечно,array
это указатель под капотом, но он не является «явным» указателем, и поэтому он может быть более интуитивно понятным для тех, кто изучает массивы, но не совсем изучил указатели.Обратите внимание на эту новую функцию:
Я определил «массив» как статический. В противном случае, когда функция завершается, переменная (и возвращаемый указатель) выходит за пределы области видимости. Поскольку эта память выделена в стеке, она будет повреждена. Обратной стороной этой реализации является то, что код не является реентерабельным и потокобезопасным.
Другой альтернативой было бы использовать malloc для выделения строки в куче, а затем освободить ее в правильных местах вашего кода. Этот код будет реентерабельным и потокобезопасным.
Как отмечено в комментарии, это очень плохая практика, поскольку злоумышленник может затем внедрить код в ваше приложение (ему / ей нужно открыть код с помощью GDB, затем создать точку останова и изменить значение возвращаемой переменной на переполнение и веселье только начинается).
Гораздо более рекомендуется позволить вызывающему абоненту обрабатывать распределение памяти. См. Этот новый пример:
Обратите внимание, что единственный контент, который может быть изменен, - это тот, который пользователь. Еще один побочный эффект - этот код теперь безопасен для потоков, по крайней мере, с точки зрения библиотеки. Программист, вызывающий этот метод, должен убедиться, что используемый раздел памяти является потокобезопасным.
источник
Ваша проблема связана с типом возвращаемого значения функции - он должен быть:
... и тогда ваша первоначальная формулировка будет работать.
Обратите внимание, что у вас не может быть строк C без задействованных указателей где-то вдоль линии.
Также: включите предупреждения компилятора. Он должен был предупредить вас о том, что строка возврата преобразует a
char *
вchar
без явного приведения.источник
Основываясь на вашей недавно добавленной предыстории с вопросом, почему бы просто не вернуть целое число от 1 до 12 для месяца и позволить функции main () использовать оператор switch или лестницу if-else, чтобы решить, что печатать? Это, конечно, не лучший способ - char * был бы - но в контексте такого класса, как я думаю, он, вероятно, самый элегантный.
источник
Вы можете создать массив в вызывающей стороне, которая является основной функцией, и передать массив вызываемой стороне, которая является вашей myFunction (). Таким образом myFunction может заполнить строку в массиве. Однако вам нужно объявить myFunction () как
А в основной функции myFunction следует вызывать так:
Однако указатель все еще используется.
источник
Тип возврата вашей функции - один символ (
char
). Вы должны вернуть указатель на первый элемент массива символов. Если вы не можете использовать указатели, значит, вы облажались. :(источник
Или как насчет этого:
И назовите это месяцем, который вы вычислили в другом месте.
источник
A
char
- это только один однобайтовый символ. Он не может хранить строку символов и не является указателем (которого у вас, по-видимому, не может быть). Следовательно, вы не можете решить свою проблему без использования указателей (чтоchar[]
является синтаксическим сахаром для).источник
Если вы действительно не можете использовать указатели, сделайте что-нибудь вроде этого:
Магическое число 9 ужасно, и это не пример хорошего программирования. Но вы поняли. Обратите внимание, что указатели и массивы - это одно и то же (своего рода), так что это немного обман.
источник
Что ж, в вашем коде вы пытаетесь вернуть
String
(в C это не что иное, как массив символов с завершающим нулем), но тип возврата вашей функции - это то,char
что вызывает у вас все проблемы. Вместо этого вы должны написать это так:И всегда полезно квалифицировать свой тип
const
при назначении литералов в C указателям, поскольку литералы в C не подлежат изменению.источник
В вашем прототипе функции указано, что ваша функция вернет символ. Таким образом, вы не можете вернуть строку в своей функции.
источник
В C строковые литералы представляют собой массивы с классом статической константной памяти, поэтому возвращение указателя на этот массив безопасно. Более подробная информация содержится в вопросе о переполнении стека «Время жизни» строкового литерала в C
источник
Строка возврата из функции
источник