Kopiowanie stringów a wskaźnik do struktury

0

Mam funkcję, która przyjmuje dwa parametry - wskaźnik do wskaźnika do struktury i string. Struktura wygląda tak:

struct human {
		int age;
		char name[20];
		struct human *next;
	};

W funkcji próbuję robić różne rzeczy, ale nic nie działa (nie udaje mi się skopiować tego stringa). Wydaje mi się, że powinno być tak:

struct human *insert(struct human **p, char *name, int age) {

	struct human *ntr;
	ntr = (struct human *)malloc(sizeof(struct human));

	while (*(ntr->name)++ = *name++);
	// dalsze instrukcje
	// return ntr;

}

Jednak nie działa, więc pewnie powinno być inaczej. Ale jak? Jak w ogóle posługiwać się stringami w strukturach?

0

ntr->name nie jest wskaźnikiem, jest tablicą. Przypisanie czegoś do symbolu tablicy nie ma sensu, stwórz wskaźnik, któremu jako wartość dasz ntr->name. Jego będziesz mógł już zmieniać.

0

Zmieniłem w deklaracji struktury na char *name i mam coś takiego:

struct human *insert(struct human **p, char *name, int age) {

	struct human *ntr;
	ntr = (struct human *)malloc(sizeof(struct human));
	
	while (*(ntr->name)++ = *name++);
	ntr->age = age;	
	ntr->next = *p;
	*p = ntr;

	return *p;

}

Ale pojawia się komunikat o "Access violation" przy while'u :)

0

W kodzie z Twojego pierwszego postu kompilator protestuje, bo nazwa tablicy wprawdzie jest wskaźnikiem ale stałym - nie można go inkrementować.
Możesz stworzyć kopię tego wskaźnika, którą już można inkrementować:

 
        char *namePtr = ntr->name;
        while (*(namePtr)++ = *name++);

Lub zamiast while użyć memcpy:

 
        // Wyznacz dlugosc imienia (+ 1 dla koncowego '\0').
        int nameLength = strlen(name) + 1;
        // Upewnij sie, ze nie przekroczymy zakresu tablicy.
        assert(nameLength <= 20); // Tutaj powinno się np. przyciąć name do 20 znaków.
        // Skopiuj.
        memcpy(ntr->name, name, nameLength);

Po zmianie "char name[20];" na "char *name;" dostajesz "Access violation", bo wskaźnikowi trzeba najpierw przydzielić pamięć :)

W ogóle, podejście z whilem jest mało wygodne bo pętla przy okazji kopiowania imienia modyfikuje też oba wskaźniki "name" i "ntr->name":

 
        // Trzeba zapamietac dlugosc imienia przed wykonaniem sie petli while.        
        int nameLength = strlen(name) + 1;        
        // Przydziel pamiec do wskaznika.
        ntr->name = malloc(nameLength);
        // Skopiuj imie.
        while (*(ntr->name)++ = *name++);
        // ntr->name (i name tez) wskazuje teraz na ostatni znak imienia ('\0')
        // i trzeba go cofnac do jego poczatku:
        ntr->name = ntr->name - nameLength;

Z memcpy prościej:

 
        int nameLength = strlen(name) + 1;
        ntr->name = malloc(nameLength);
        memcpy(ntr->name, name, nameLength);

Użycie wskaźnika zamiast tablicy ma taką zaletę, że użytkownik może podać imię dłuższe niż 20 znaków - program przydzieli dokładnie tyle pamięci ile potrzeba, podczas gdy tablica mogłaby się okazać za mała.

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.