Malloc(), łańcuchy i wskaźniki.

0

Witam. Potrzebuję pomocy w następującym zadaniu.

"Napisz program, który najpierw zapyta operatora o liczbę słów do wprowadzenia, następnie przyjmie słowa na wejście, a potem wypisze wszystkie wprowadzone słowa.
Program powinien użyć pamięci przydzielanej dynamicznie (za pomocą funkcji malloc()) na podstawie wprowadzonej liczby słów do utworzenia
tablicy wskaźników do typu char (skoro każdy element tablicy będzie wskaźnikiem do typu char, wskaźnik użyty do przechowania wartości zwracanej z wywołania malloc() powinien być typu wskaźnika do wskaźnika do typu char).
Kolejne słowa powinny być wczytywane do tymczasowej tablicy znaków, aby potem za pomocą wywołania malloc() przydzielić dla słowa obszar wystarczający do przechowania tego słowa; po skopiowaniu słowa do przydzielonego obszaru pamięci program powinien zapisać adres przydzielonego obszaru w kolejnym elemencie
tablicy.
Ostatecznie program powinien więc wytworzyć tablicę wskaźników, z których każdy wskazuje do obiektu o rozmiarze dokładnie odpowiadającym rozmiarowi przechowywanego w nim ciągu znaków. Przykładowe uruchomienie programu powinno wyglądać tak:
Podaj liczbe slow do wprowadzenia: 5
Wprowadz 5 slow:
calkiem niezle cwiczenie z pamiecia
Oto wprowadzone slowa:
calkiem
niezle
cwiczenie
z
pamiecia
"

Nasuwa mi się parę pytań, a mianowicie:
-W jaki sposób utworzyć dynamiczną tablicę wskaźników do char? (Wiem, że niedynamicznie wygląda to tak: char * wsk[rozmiar];)
Spotkałem się jedynie z tworzeniem zwykłej dynamicznej tablicy:

char * tab = (char *) malloc(rozmiar * sizeof(char));

-Po wczytaniu słów do dynamicznej tablicy znaków, w jaki sposób mam obliczyć długość każdego słowa, żeby później utworzyć odpowiednią ilość miejsca na każde z nich?

0

char * tab = (char *) malloc(rozmiar * sizeof(char));
Tak zrobisz dynamiczną tablicę char. Jak chcesz zrobić dynamiczną tablicę char* to zamiast char napisz char*.

Jeśli to dla ciebie problem, to użyj typedef aby ukryć, że mowa o wskaźniku:

typedef char X;
typedef char* Y;
X * tab = (X *) malloc(rozmiar * sizeof(X));
Y * tab = (Y *) malloc(rozmiar * sizeof(Y));

Tu masz tablicę wskaźników na char i tablicę charów

-Po wczytaniu słów do dynamicznej tablicy znaków, w jaki sposób mam obliczyć długość każdego słowa, żeby później utworzyć odpowiednią ilość miejsca na każde z nich?

strlen. Przy czym zadanie mówi o wczytaniu do tymczasowej statycznej tablicy.

0
char ** tab = (char **) malloc(rozmiar * sizeof(char*));

i musisz zaalokować pamięć dla każdego z tych wskaźników

0

Na ten moment udało mi się stworzyć ten program, który w teorii działa jak powinien. Oczywiście jeśli nie na początku nie ma odstępów oraz występuje tylko jedna spacja między każdym słowem. Co byście tutaj zmienili, żeby być może zwiększyć czytelność programu bądź bardziej go zoptymalizować? Mam również pytanie odnośnie zwalniania pamięci funkcją free(). Czy została ona odpowiednio użyta w następującym kodzie czy wystarczyło zwolnić pamięć pojedynczą instrukcją free(wsk)?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ROZMIAR 1000

int main (void)
{
int words, poczatek=0, koniec;
char arr[ROZMIAR];

printf("Podaj liczbe slow do wprowadzenia: ");
scanf("%d",&words);

while(getchar()!='\n')
    continue;

char ** wsk = (char **) malloc(words * sizeof(char *)); //tablica wskaznikow do char


printf("Wprowadz %d slow(MAX %d ZNAKOW):\n",words,ROZMIAR);
fgets(arr,ROZMIAR,stdin);

for(int i=0, x=0; i<strlen(arr) && x<words; i++)    //petla liczaca dlugosc kazdego slowa,
{                                                   //dziala do konca lancucha badz do przekroczenia wpisanej liczby slow
    if(arr[i] == ' ' || i == strlen(arr) - 1)
    {
        koniec = i;

        wsk[x] = (char *) malloc(((koniec - poczatek) + 1) * sizeof(char));   //stworzenie tablicy char dla odpowiedniej dlugosci slowa (+1 dla zerowego znaku)
        strncpy(wsk[x],arr + poczatek, (koniec - poczatek));
        strcpy(wsk[x] + (koniec - poczatek), "\0");  // doklejenie znaku zerowego na koniec tablicy


        poczatek = i+1;
        x++;
    }
}

puts("Oto wprowadzone slowa:");
for(int i=0; i<words; i++)      //wyswietlenie zawartosci i zwolnienie z pamieci kazdej tablicy
{
    printf("%s\n",wsk[i]);
    free(wsk[i]);
}


free(wsk);

return 0;
}
2

Z tym getchar to niezły trick :) Ale to nie musi działać. Może użyj scanf( "%999s", &arr[0] ) w pętli, wtedy nie będziesz miał problemu z białymi znakami.
Do dopisania na końcu znaku '\0' wystarczy *( wsk[x] + ( koniec - początek )) = '\0', nie trzeba do tego wołać funkcji strcpy. Ale jeśli użyjesz scanf, to masz zagwarantowane dopisanie znaku '\0'.
Funkcji free musisz użyć do zwolnienia osobno każdego bloku przydzielonego funkcją malloc, nie wystarczy zwolnić tylko tablicę wskaźników, ale – tak jak napisałeś – trzeba też zwolnić każdy blok pamięci przypisany do wskaźnika (elementu tablicy).

0
overcq napisał(a):

Z tym getchar to niezły trick :)

W sam raz na nieskończoną pętlę (np koniec pliku).

scanf("%*[^\n] ");

https://godbolt.org/z/jjdhE6

1

A tu jak pisać czytelny kod C: https://godbolt.org/z/aT5qEY

0

A nie lepiej po prostu jak zamiast tej pętli

while(getchar()!='\n')
    continue;

wyczyszczę bufor (fflush(stdin)) i wtedy fgets nie wczyta znaku nowej linii?

1 użytkowników online, w tym zalogowanych: 0, gości: 1