Возврат струны до от функции

  1. Полагают, что переключение БЕЗДЕЙСТВУЕТ. F5 делает все.

  2. Рассматривают переключение на Комодо. Можно определить команду так, чтобы F5 сделал все.

98
задан Mat 16 March 2013 в 09:51
поделиться

10 ответов

подпись вашей функции должна быть:

const char * myFunction()
{
    return "My String";
}

Изменить:

Предыстория:

Прошло много лет с момента создания этого сообщения, и никогда не думал, что за него проголосуют, потому что это так важно для C и C ++. Тем не менее, следует провести еще немного обсуждения.

В C (и C ++, если на то пошло) строка представляет собой просто массив байтов, оканчивающихся нулевым байтом - следовательно, термин "строка-ноль" используется для представляют этот конкретный аромат строки. Существуют и другие типы строк, но в C (и C ++) эта разновидность по сути понимается самим языком. Другие языки (Java, Pascal и т. Д.) Используют разные методологии для понимания «моей строки».

Если вы когда-либо использовали Windows API (который находится на C ++), вы довольно часто будете видеть параметры функции, такие как: «LPCSTR lpszName» . ' sz 'часть представляет это понятие' строка-ноль ': массив байтов с нулевым символом конца (/ ноль).

Уточнение:

Для этого «вступления» я использую слово «байты» и «персонажи» - синонимы, потому что так легче выучить. Имейте в виду, что существуют другие методы (расширенные символы и многобайтовые системы символов - mbcs), которые используются для работы с международными символами. UTF-8 - это пример файла mbcs. Ради вступления я просто «пропускаю» все это.

Память:

Это означает, что строка, подобная «моей строке», на самом деле использует 9 + 1 (= 10!) Байтов. Это важно знать, когда вы наконец дойдете до динамического распределения строк.

Уточнение:

Ради этого «вступления» я использую слова «байты» и «символы» как синонимы, потому что так легче выучить. Имейте в виду, что существуют другие методы (расширенные символы и многобайтовые системы символов - mbcs), которые используются для работы с международными символами. UTF-8 - это пример файла mbcs. Ради вступления я просто «пропускаю» все это.

Память:

Это означает, что строка, подобная «моей строке», на самом деле использует 9 + 1 (= 10!) Байтов. Это важно знать, когда вы наконец дойдете до динамического распределения строк.

Уточнение:

Ради этого «вступления» я использую слова «байты» и «символы» как синонимы, потому что так легче выучить. Имейте в виду, что существуют другие методы (расширенные символы и многобайтовые системы символов - mbcs), которые используются для работы с международными символами. UTF-8 - это пример файла mbcs. Ради вступления я просто «пропускаю» все это.

Память:

Это означает, что строка типа «моя строка» на самом деле использует 9 + 1 (= 10!) Байтов. Это важно знать, когда вы наконец дойдете до динамического распределения строк. и многобайтовые системы символов - mbcs), которые используются для работы с международными символами. UTF-8 - это пример файла mbcs. Ради вступления я просто «пропускаю» все это.

Память:

Это означает, что строка, подобная «моей строке», на самом деле использует 9 + 1 (= 10!) Байтов. Это важно знать, когда вы наконец дойдете до динамического распределения строк. и многобайтовые системы символов - mbcs), которые используются для работы с международными символами. UTF-8 - это пример файла mbcs. Ради вступления я просто «пропускаю» все это.

Память:

Это означает, что строка типа «моя строка» на самом деле использует 9 + 1 (= 10!) Байтов. Это важно знать, когда вы наконец дойдете до динамического распределения строк. Итак, без этого «завершающего нуля» у вас не будет строки. У вас есть массив символов (также называемый буфером), зависший в памяти.

Долговечность данных:

Использование функции следующим образом:

const char * myFunction()
{
    return "My String";
}
int main() 
{
    const char* szSomeString = myFunction(); // fraught with problems
    printf("%s", szSomeString);
}

... обычно приводит к случайным необработанным исключениям / сегментные неисправности и т.п., особенно «в будущем».

Короче говоря, хотя мой ответ правильный - в 9 случаях из 10 вы получите программу, которая дает сбой, если вы используете ее таким образом, особенно если вы считаете, что это «хорошая практика». Вкратце: Обычно это не так.

Например, представьте, что когда-нибудь в будущем, строку теперь нужно каким-то образом изменить. Как правило, программист «выбирает легкий путь» и (пытается) писать такой код:

const char * myFunction(const char* name)
{
    char szBuffer[255];
    snprintf(szBuffer, sizeof(szBuffer), "Hi %s", name);
    return szBuffer;
}

То есть, ваша программа выйдет из строя, потому что компилятор (мог или не мог) освободил память, используемую szBuffer , к тому времени, когда printf () в main () будет называется. (Ваш компилятор также должен заранее предупредить вас о таких проблемах).

Есть два способа вернуть строки, которые не так быстро прерываются.

  1. возвращение буферов (статических или динамически выделяемых), которые существуют некоторое время. В C ++ используйте «вспомогательные классы» (например, std :: string ) для обработки долговечности данных (что требует изменения возвращаемого значения функции) или
  2. передайте буфер функции, которая заполняется in с информацией.

Обратите внимание, что невозможно использовать строки без указателей в C. Как я показал, они синонимы. Даже в C ++ с шаблонными классами всегда в фоновом режиме используются буферы (т.е. указатели).

Итак, чтобы лучше ответить на (теперь измененный вопрос). (наверняка будет множество «других ответов», которые могут быть предоставлены).

Более безопасные ответы:

например 1. использование статически распределенных строк:

const char* calculateMonth(int month) 
{
    static char* months[] = {"Jan", "Feb", "Mar" .... }; 
    static char badFood[] = "Unknown";
    if (month<1 || month>12) 
        return badFood; // choose whatever is appropriate for bad input. Crashing is never appropriate however.
    else
        return months[month-1];
}
int main()
{
    printf("%s", calculateMonth(2)); // prints "Feb"
}

Что здесь делает «static» (многие программисты делают в отличие от этого типа «распределения») состоит в том, что строки помещаются в сегмент данных программы. То есть, он размещен постоянно.

Если вы перейдете на C ++, вы будете использовать аналогичные стратегии:

class Foo 
{
    char _someData[12];
public:
    const char* someFunction() const
    { // the final 'const' is to let the compiler know that nothing is changed in the class when this function is called.
        return _someData;
    }   
}

... но, вероятно, проще использовать вспомогательные классы, такие как std :: string , если вы пишете код для собственного использования (а не часть библиотеки для совместного использования с другими). ​​

например, 2. с использованием буферов, определяемых вызывающим абонентом:

Это более «защита от дурака» способ передачи струн. Возвращенные данные не могут быть изменены вызывающей стороной. То есть, например, 1 может быть легко использован вызывающей стороной и подвергнут вас ошибкам приложения. Таким образом, это намного безопаснее (хотя и требует большего количества строк кода):

void calculateMonth(int month, char* pszMonth, int buffersize) 
{
    const char* months[] = {"Jan", "Feb", "Mar" .... }; // allocated dynamically during the function call. (Can be inefficient with a bad compiler)
    if (!pszMonth || buffersize<1) 
        return; // bad input. Let junk deal with junk data.
    if (month<1 || month>12)
    {
        *pszMonth = '\0'; // return an 'empty' string 
        // OR: strncpy(pszMonth, "Bad Month", buffersize-1);
    }
    else
    {
        strncpy(pszMonth, months[month-1], buffersize-1);
    }
    pszMonth[buffersize-1] = '\0'; // ensure a valid terminating zero! Many people forget this!
}

int main()
{
    char month[16]; // 16 bytes allocated here on the stack.
    calculateMonth(3, month, sizeof(month));
    printf("%s", month); // prints "Mar"
}

Существует множество причин, по которым второй метод лучше, особенно если вы пишете библиотеку для использования другими (вам не нужно заблокировать конкретную схему распределения / освобождения, третьи стороны не могут сломать ваш код, вам не нужно связываться с конкретной библиотекой управления памятью), но, как и весь код, вам решать, что вам больше нравится. По этой причине большинство людей выбирают, например, 1, пока их не сожгли столько раз, что они больше отказываются писать это таким образом;)

отказ от ответственности:

Я ушел на пенсию несколько лет назад, и мой C немного ржавый сейчас.

202
ответ дан 24 November 2019 в 05:10
поделиться

Note this new function:

const char* myFunction()
{
        static char array[] = "my string";
        return array;
}

I defined "array" as static, otherwise when the function end, the variable (and the pointer you are returning) gets out of scope. Since that memory is allocated on the stack, it will get corrupted. The downside of this implementation is that the code is not re-entrant and not thread-safe.

Another alternative would be to use malloc to allocate the string in the heap, and then free on the correct locations of your code. This code will be re-entract and thread safe.

EDIT:

As noted in the comment, this is a very bad practice, since an attacker can then inject code to your app (he needs to open the code using gdb, then make a breakpoint and modify the value of a returned variable to overflow and fun just gets started).

If is much more recommended to let the caller handle about memory allocations. See this new example:

char* myFunction( char* output_str, size_t max_len )
{
   const char *str = "my string";
   size_t l = strlen(str);
   if (l+1 > max_len) {
      return NULL;
   }
   strcpy(str, str, l);
   return input;
}

Note that the only content which can be modified is the one that the user. Another side effect - this code is now thread safe, at least from the library point of view. The programmer calling this method should verify that the memory section used is thread safe.

9
ответ дан 24 November 2019 в 05:10
поделиться

Строка AC определяется как указатель на массив символов.

Если у вас нет указателей, по определению у вас не может быть строк.

12
ответ дан 24 November 2019 в 05:10
поделиться

Ваша проблема связана с типом возвращаемого значения функции - он должен быть:

char *myFunction()

... и тогда ваша исходная формулировка будет работать.

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

Также: включите предупреждения компилятора, он должен был предупредить вас об этой строке возврата, преобразующей char * в char без явного приведения.

8
ответ дан 24 November 2019 в 05:10
поделиться

Based on your newly-added backstory with the question, why not just return an integer from 1 to 12 for the month, and let the main() function use a switch statement or if-else ladder to decide what to print? It's certainly not the best way to go - char* would be - but in the context of a class like this I imagine it's probably the most elegant.

5
ответ дан 24 November 2019 в 05:10
поделиться

Тип возврата вашей функции - одиночный символ. Вы должны вернуть указатель на первый элемент массива символов. Если вы не можете использовать указатели, значит, вы облажались. : (

2
ответ дан 24 November 2019 в 05:10
поделиться

Or how about this one:

void print_month(int month)
{
    switch (month)
    {
        case 0:
            printf("january");
            break;
        case 1:
            printf("february");
            break;
        ...etc...
    }
}

And call that with the month you compute somewhere else.

Regards,

Sebastiaan

2
ответ дан 24 November 2019 в 05:10
поделиться

char - это только один однобайтовый символ. Он не может хранить строку символов и не является указателем (которого у вас, по-видимому, не может быть). Поэтому вы не можете решить свою проблему без использования указателей (для которых char [] является синтаксическим сахаром).

1
ответ дан 24 November 2019 в 05:10
поделиться

If you really can't use pointers, do something like this:

char get_string_char(int index)
{
    static char array[] = "my string";
    return array[index];
}

int main()
{
    for (int i = 0; i < 9; ++i)
        printf("%c", get_string_char(i));
    printf("\n");
    return 0;
}

The magic number 9 is awful, this is not an example of good programming. But you get the point. Note that pointers and arrays are the same thing (kinda) so this is a bit cheating.

Hope this helps!

1
ответ дан 24 November 2019 в 05:10
поделиться

В прототипе вашей функции указано, что функция вернет символ. Таким образом, вы не можете вернуть строку в своей функции.

0
ответ дан 24 November 2019 в 05:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: