podpis funkcja musi być:
const char * myFunction()
{
return "My String";
}
Edit:
Tło:
Minęły lata od tego postu & nigdy nie myślałem, że będzie głosował w górę, ponieważ jest tak fundamentalny dla C & C++. Niemniej jednak należy przeprowadzić nieco więcej dyskusji.
W C (& C++), ciąg jest po prostu tablicą bajtów zakończonych bajtem zerowym - stąd termin "string-zero" jest używany do reprezentowania tego konkretnego smaku ciągu. Istnieją inne rodzaje łańcuchów, ale w C (& C++) ten smak jest z natury zrozumiały dla samego języka. Inne języki (Java, Pascal, itp.) Używają różnych metodologii, aby zrozumieć "mój ciąg".
Jeśli kiedykolwiek użyjesz Windows API (który jest w C++), zobaczysz dość regularnie parametry funkcji takie jak: "LPCSTR lpszName". Część "sz" reprezentuje to pojęcie "string-zero": tablica bajtów z terminatorem zerowym (/ zero).
Wyjaśnienie:
Dla tego „intra”, używam słowa „bajty” i „znaki” zamiennie, ponieważ łatwiej jest uczyć się w ten sposób. Należy pamiętać, że istnieją inne metody (szerokie znaki i wielobajtowe systemy znakowe - mbcs), które są używane w celu radzenia sobie ze znakami międzynarodowymi. UTF-8 jest przykładem mbcs. Ze względu na intro, po cichu "pomijam" to wszystko.
Pamięć:
Oznacza to, że ciąg jak "my string" rzeczywiście wykorzystuje 9 + 1 (= 10!) Bajtów. Ważne jest, aby wiedzieć, kiedy w końcu dostaniesz się do dynamicznego przydzielania ciągów. Tak więc, bez tego "zera kończącego", nie masz łańcucha. Masz w pamięci tablicę znaków (zwaną także buforem).
Longevity danych:
Zastosowanie funkcji w ten sposób:
const char * myFunction()
{
return "My String";
}
int main()
{
const char* szSomeString = myFunction(); // fraught with problems
printf("%s", szSomeString);
}
... generalnie lądować Ci losowych nieobsłużonych-wyjątkami/usterek segmentu i tym podobne, zwłaszcza " w dół drogi'.
W skrócie, chociaż moja odpowiedź jest poprawna - 9 razy na 10 skończy się program, który ulega awarii, jeśli używasz go w ten sposób, szczególnie jeśli uważasz, że to "dobra praktyka", aby zrobić to w ten sposób . Krótko mówiąc: na ogół nie.
Na przykład, wyobraźmy sobie jakiś czas w przyszłości, ciąg musi zostać w jakiś sposób zmanipulowany. Generalnie, koder „będzie mieć prostą drogę” i (spróbuj) napisać kod jak poniżej:
const char * myFunction(const char* name)
{
char szBuffer[255];
snprintf(szBuffer, sizeof(szBuffer), "Hi %s", name);
return szBuffer;
}
Oznacza to, że program będzie katastrofy, ponieważ kompilator (może/nie może) wydali pamięć używaną przez szBuffer
do czasu wywołania printf()
w main()
. (Twój kompilator powinien uprzednio ostrzec Cię przed takimi problemami).
Istnieją dwa sposoby zwracania ciągów, które nie będą tak łatwo barfować.
- zwracające bufory (statycznie lub dynamicznie przydzielane), które działają przez jakiś czas. W C++ użyj "klas pomocniczych" (np.
std::string
) do obsługi długowieczności danych (co wymaga zmiany wartości zwracanej przez funkcję), lub
- przekazania bufora do funkcji, która zostanie wypełniona informacjami.
Należy zauważyć, że niemożliwe jest użycie ciągów bez użycia wskaźników w C. Jak już pokazałem, są one synonimami. Nawet w C++ z klasami szablonów zawsze są używane bufory (np. Wskaźniki) w tle.
Aby lepiej odpowiedzieć na (teraz zmodyfikowane pytanie). (z pewnością można uzyskać wiele "innych odpowiedzi", które można zapewnić).
Bezpieczniejsze Odpowiedzi:
np 1. Korzystając statycznie przydzielone ciągi:
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"
}
Co 'static' robi tutaj (wielu programistów nie lubią tego typu 'alokacja') jest to, że łańcuchy zostają umieszczone w segmencie danych programu. Oznacza to, że jest przydzielany na stałe.
Jeśli przejście na C++ użyjesz podobne strategie:
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;
}
}
... ale to chyba łatwiejsze w użyciu klas pomocniczych, takich jak std::string
, jeśli piszesz kod dla własnego używać (i nie być częścią biblioteki do dzielenia się z innymi).
np 2. Używanie rozmówcy zdefiniowane bufory:
jest to bardziej „głupi dowód” sposób przekazywania sznurki wokół. Zwrócone dane nie podlegają manipulacji ze strony wywołującej. Oznacza to, że np. 1 osoba może łatwo zostać wykorzystana przez stronę dzwoniącą i narazić Cię na błędy aplikacji. W ten sposób jest znacznie bezpieczniejsze (choć używa więcej linii kodu):
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"
}
Istnieje wiele powodów, dlaczego 2nd metoda jest lepsza, zwłaszcza jeśli piszesz biblioteki do wykorzystania przez innych (don nie musi blokować twojego kodu, nie musisz łączyć się z określoną biblioteką zarządzania pamięcią), ale jak każdy kod, wszystko zależy od tego, co lubisz Najlepiej. Z tego powodu większość ludzi wybiera np.1 aż zostały one spalone tak wiele razy, że nie chcą, aby napisać to w ten sposób już;)
Zastrzeżenie:
I wycofał się kilka lat temu, a mój C jest teraz trochę zardzewiały. Ten kod demo powinien wszystko poprawnie skompilować z C (dla jakiegokolwiek kompilatora C++ jest w porządku).
Niestety * potrzebujesz * wskaźników w tym przypadku. –
Dlaczego nie możesz używać wskaźników? –
(musisz zwrócić int w main przy okazji) – user224579