Funkcja zwracająca stringa

Funkcja zwracająca stringa
GO
  • Rejestracja:około 6 lat
  • Ostatnio:14 dni
  • Postów:92
0

Witam
Piszę funkcję, która ma pobrać imię użytkownika(np. JOHN) i zwrócić stringa w postaci "Hello, John!". Jeśli string imię jest pusty ma zwrócić "Hello, world!"Poniżej wklejam kod i nie wiem gdzie jest błąd bo serwer wyrzuca mi błąd free(): invalid pointer.

Kopiuj
#include <stdlib.h>

char *hello(const char *name) {
  int i;
	if (name=="")
		return "Hello, World!";
	char *tmp = (char*)malloc(sizeof(char)*strlen(name));
  char *result=(char*)malloc(sizeof(char)*200);
  tmp[0]=toupper(name[0]);
  for(i=1;i<strlen(name);i++)
    tmp[i]=tolower(name[i]);
 tmp[i]='\0';
  sprintf(result,"Hello, %s!",tmp);
  return result;
}
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:2 dni
  • Lokalizacja:Szczecin
3

(name=="") tak się nie porównuje stringów w C - użyj strcmp

Kopiuj
for(i=1;i<strlen(name);i++)
    tmp[i]=tolower(name[i]);

użyj strcpy

całość generalnie można sprowadzić do:

Kopiuj
char* hello(const char* name)
{
    if(!name || !*name)
        name = "World";
    char* result = malloc(strlen(name) + sizeof("Hello, "));
    sprintf(result, "Hello, %c%s", toupper(name[0]), name+1);
    return result;
}

Co do invalid free to ciekawe, bo akurat takiego błędu bym się nie spodziewał.


AK
  • Rejestracja:prawie 7 lat
  • Ostatnio:około 2 miesiące
  • Postów:3561
4
gonskabalbinka napisał(a):

Witam
Piszę funkcję, która ma pobrać imię użytkownika(np. JOHN) i zwrócić stringa w postaci "Hello, John!". Jeśli string imię jest pusty ma zwrócić "Hello, world!"Poniżej wklejam kod i nie wiem gdzie jest błąd bo serwer wyrzuca mi błąd free(): invalid pointer.

Kopiuj
#include <stdlib.h>

char *hello(const char *name) {
  int i;
	if (name=="")
		return "Hello, World!";
	char *tmp = (char*)malloc(sizeof(char)*strlen(name));
  char *result=(char*)malloc(sizeof(char)*200);
  tmp[0]=toupper(name[0]);
  for(i=1;i<strlen(name);i++)
    tmp[i]=tolower(name[i]);
 tmp[i]='\0';
  sprintf(result,"Hello, %s!",tmp);
  return result;
}

masz wyciek(i) pamięci

  • z zaniedbania tmp powinieneś zwolnić, ale tego nie robisz (a mógłbyś)
  • drugi problem jest o wiele bardziej istotny i złożony. Nie możesz zwolnić result, bo zwracasz do miejsca wywołania.
    Wniosek: wywołujący powinien wykorzystać i zwolnić.
    Ale wtedy kaszana się robi z return "Hello, World!"; skądże wywołującemu wiedzieć, ze tym razem nie jest to alokowana tablica, tylko stały string. Jest to poważny UB, który kopnie w pupę z opóźnieniem
    ten problem jest typowy dla podobnych funkcji C, jest to jedna ze słabości tego języka, i wymaga dobrego określenia (dokumentacji) jak używać funkcję ("funkcja zwraca nowo alokowaną tablicę, którą należy zwolnić"), i zdyscyplinowanego programisty, który będzie jej posłuszny. Niestety, w C nie ma stosownych "bezpieczników", tylko człowiek.

Bo C to najlepszy język, każdy uczeń ci to powie
edytowany 2x, ostatnio: AnyKtokolwiek
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około godziny
2
AnyKtokolwiek napisał(a):

Ale wtedy kaszana się robi z return "Hello, World!"; skądże wywołującemu wiedzieć, ze tym razem nie jest to alokowana tablica, tylko stały string.

W takich przypadkach, dokumentacja (khe, khe) powinna jasno mówić, że obiekt zwracany przez funkcję Foo() ma być zwalniany funkcją free() czy jakimś innym DeleteFoo() – a Foo() wtedy musi zawsze zwracać obiekt zwalnialny tą funkcją. Czyli nie może raz robić return "Hello, world", a za innym razem używać malloc.

ten problem jest typowy dla podobnych funkcji C, jest to jedna ze słabości tego języka, i wymaga dobrego określenia (dokumentacji) jak używać funkcję > ("funkcja zwraca nowo alokowaną tablicę, którą należy zwolnić"), i zdyscyplinowanego programisty, który będzie jej posłuszny.

Za to zachęca do czytania dokumentacji, a nie tylko listy metod pod ctrl+spacja :)

Przykład takiej dokumentacji - funkcja GetDC() z WinAPI. W sekcji Remarks napisano kiedy trzeba (a kiedy nie) użyć ReleaseDC:
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc

After painting with a common DC, the ReleaseDC function must be called to release the DC.
Class and private DCs do not have to be released. ReleaseDC must be called from the same thread that called GetDC.
The number of DCs is limited only by available memory.

edytowany 5x, ostatnio: Azarien
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

Poza juz wymienionymi błędami, jest tu też overflow, bo nigdzie nie ma sprawdzenia czy aby na pewno cała wiadomość nie będzie dłuższa niż ten 200 znakowy bufor. Rozmiar bufora result powinien mieć strlen(name)+strlen("Hello, !")+1 a nie jakieś losowo dobrane 200. Tak jak zresztą pokazał kq w swoim poście.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
GO
  • Rejestracja:około 6 lat
  • Ostatnio:14 dni
  • Postów:92
0

Dzięki za odpowiedzi i uwagi

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.