malloc dokonujący zmian w całym programie, a nie tylko w funkcji

0

Cześć. Napisałem taki krótki program dla poćwiczenia. Funkcja dostaje napis, jej zadaniem jest zamiana każdego napotkanego A na BB. Jak działa to chyba widoczne: jeżeli napotka jakieś A, to kopiuje tablicę do tymczasowej, powiększa tablicę i wypełnia ją.

void funkcja (char*tab, int rozmiar) {
    int i,k;
    char*tmp;
    for (k=0; tab[k]!='\0'; k++)
        if (tab[k]=='A') {
            tmp = malloc( (rozmiar) * sizeof *tab );
            for (i=0; i<rozmiar-1; i++) {
                tmp[i]=tab[i];
            }
            tab = malloc( (rozmiar+1) * sizeof *tab );
            for (i=0; i<rozmiar-2; i++) {
                if (i<k)
                    tab[i]=tmp[i];
                else
                    tab[i+2]=tmp[i+1];
            }
            free (tmp);
            tab[k]='B';
            tab[k+1]='B';
            rozmiar=rozmiar+1;
            k=k+1;
        }
}


int main() {
    int i;
    char napis[] = "BACAC";

    funkcja(napis, 6);


    for (i=0; napis[i]!='\0'; i++)
        printf("%c", napis[i]);

    EXIT_SUCCESS;
}

No i jeżeli wyświetlam tablicę w main, to jest ona w niezmodyfikowanej wersji, a jeżeli wyświetlam ją w funkcji to jest ok. Problemem jest malloc, który alokuje pamięć tylko w obrębie funkcji. Czy jest jakiś sposób, żeby malloc użyty w funkcji zadziałał na tablicę w całym programie? Będę bardzo wdzięczny za pomoc :)

0

Ech, czy ta sprawa jest tak trudna czy tak żenująco łatwa, że nikt mi nie odpowiada? ;p

1

Nie jest trudna... Musisz to zrobić inaczej, albo zwracać wskaźnik, albo przekazać wskaźnik na wskaźnik (czyli

 void funkcja (char **tab, int rozmiar)

dalsze zmiany zgodnie z konsekwencjami tej zmiany w kodzie.

2

Problem to nie malloc tylko fakt że funkcja pracuje na kopii argumentów. Jeśli do funkcji przekazałaś zmienną x to zmiana jej wartości w funkcji NIE JEST widoczna poza funkcją. Przykład:

void test(int x){
    x = 2;
    printf("%d", x);
}

int main(){
    int x = 1;
    printf("%d", x);
    test(x);
    printf("%d", x);
    return  0;
}

Zadaj sobie pytanie: co wypisze ten kod?

Najwygodniej będzie ci zwrócić z tej funkcji nowy wskaźnik. Wtedy masz taką sytuacje:

int test(int x){
    x = 2;
    printf("%d", x);
    return x;
}

int main(){
    int x = 1;
    printf("%d", x);
    int x_new = test(x);
    printf("%d", x);
    printf("%d", x_new);
    return  0;
}
0

Dziękuję bardzo za odpowiedzi.

Wiem, że funkcje działają na kopiach argumentów, ale wydawało mi się, że na oryginałach tablic. Jeżeli zrobię jakąś funkcję void z argumentem char*tab bez malloca, to wartości oryginalnej tablicy zostaną zmienione.

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

char *funkcja (char*tab, int rozmiar) {
    int i,k;
    char*tmp;
    for (k=0; tab[k]!='\0'; k++)
        if (tab[k]=='A') {
            tmp = malloc( (rozmiar) * sizeof *tab );
            for (i=0; i<rozmiar-1; i++) {
                tmp[i]=tab[i];
            }
            tab = malloc( (rozmiar+1) * sizeof *tab );
            for (i=0; i<rozmiar-2; i++) {
                if (i<k)
                    tab[i]=tmp[i];
                else
                    tab[i+2]=tmp[i+1];
            }
            free (tmp);
            tab[k]='B';
            tab[k+1]='B';
            rozmiar=rozmiar+1;
            k=k+1;
        }
    return tab;
}


int main() {
    int i;
    char*napis = "BACAC";

    napis = funkcja(napis, 6);

    for (i=0; napis[i]!='\0'; i++)
        printf("%c", napis[i]);

    EXIT_SUCCESS;
}

Po zmianach funkcja działa poprawnie, tylko chciałbym zrobić to jak najbardziej "świadomie", a jestem właśnie na etapie próby jak najlepszego opanowania wskaźników. :) W obecnej formie:

  • funkcja dostaje w argumencie wskaźnik do tablicy charów
  • funkcja robi sobie lokalną kopię wskaźnika
  • za pomocą lokalnej kopii wskaźnika funkcja zmienia oryginalną tablicę
  • zwrócony jest wskaźnik do zmienionej tablicy.

Dobrze to rozumiem?

5

Genralnie tak. Zauważ że wskaźnik to jest pewna liczba która określa numer komórki pamięci.
Wyobraźmy sobie że pokazałeś mi swoją wizytówkę a ja adres z niej przepisze na kolejną kartkę (zrobie kopię jak podczas wołania funkcji) to co się stanie? Nadal mogę pojechać do ciebie do domu na imprezę bo adres sie nie zmienił. Chatę też ci mogę spalić i niewątpliwie chata zostanie spalona, nawet jeśli przyjechałem na podstawie skopiowanej kartki z adresem. Ale jeśli wezmę teraz tą moją skopiowaną kartkę i zmienie adres który na niej widnieje to adres na twojej wizytówce nie ulegnie zmianie.
Twoja wizytówka to wskaźnik do tablicy. Moja przepisana kartka to lokalna kopia wskaźnika utworzona na potrzeby funkcji. Tablica to twój dom.

0

Wielkie dzięki za pomoc i za niebanalne wyjaśnienie! ;d

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