Tablica alokowana w strukturze i dostęp z zewnątrz [C]

0

Mam następujący problem. Napisałem sobie strukturę:

 
struct strOut
{
	uint8_t ownNumber;
	uint8_t modulWidth;
	uint8_t modulsAmount;
	uint8_t modulType;
	uint8_t font;
	uint8_t color;
	uint8_t speed;
	uint8_t effect;
	uint8_t brightness;
	uint8_t hardwareOutNumber;
	uint8_t align;
	uint16_t *buffer;
	char *text;
	
	void (*StatFun)(struct strOut*);
	void (*StepFun)(struct strOut*);
};

typedef struct strOut Out;
extern Out Out_JP1, Out_JP2;

Następnie zainicjalizowałem sobie te strukturę poprzez wywołanie funkcji:

 
void InitStruct(Out *str)
{
	//odczytywanie wartości z pamięci eeprom
	str->hardwareOutNumber = eeprom_read_byte(&ee_hardwareOutNumber_out[str->ownNumber]);
	str->brightness = eeprom_read_byte(&ee_brightness_out[str->ownNumber]);
	str->modulsAmount = eeprom_read_byte(&ee_modulsAmount_out[str->ownNumber]);
	str->modulType = eeprom_read_byte(&ee_modulType_out[str->ownNumber]);
	str->modulWidth = eeprom_read_byte(&ee_modulWidth_out[str->modulWidth]);
	
	//zerowanie pozostałych pól stuktury
	str->font = 0;
	str->color = 0;
	str->speed = 0;
	str->effect = 0;
	str->align = ALIGN_CENTER;
	
	//alokacja pamięci dla bufora
	str->buffer = (uint16_t*) calloc (str->modulsAmount*str->modulWidth, sizeof(uint16_t));
	
	//alokacja pamięci dla tablicy znaków
	str->text = (char*) calloc (str->modulsAmount*(str->modulWidth), sizeof(char));
}

Teraz w funkcji main robie sobie coś takiego:

 
Out_JP1.text[0] = 'a';
Out_JP1.text[1] = 'b';
Out_JP1.text[2] = 'c';
Out_JP1.text[3] = 0x00;
Out_JP2.text[0] = '1';
Out_JP2.text[1] = '2';
Out_JP2.text[2] = '3';
Out_JP2.text[3] = 0x00;

A następnie w petli nieskończonej:

 
while(1)
    {
		ShowTextStart(&Out_JP1);
		ShowTextStart(&Out_JP2);
		_delay_ms(500);
		Out_JP1.text = &Out_JP1.text[0];
		Out_JP2.text = &Out_JP2.text[0];
    }

Funkcja ShowTextStart przesuwa mi wskaźnik po kolejnych elementach struktury, czyli wywołuje kilkukrotnie str->text++ (tak upraszczając);

Po wykonaniu funkcji chciałbym wrócić na pierwsza pozycje tablicy, jeśli zamiast

Out_JP1.text = &Out_JP1.text[0];
Out_JP2.text = &Out_JP2.text[0];

wstawię:

Out_JP1.text = Out_JP1.text -= 3;
Out_JP2.text = &Out_JP2.text -= 3;

to wszystko jest ok, bo funkcja ShowTextStart przesuwa wskaźnik o 3 pozycje (str->text += 3);
Ale przesunięcie w funkcji ShowTextStart może być różne.

Nie wiem jak mam traktować zapis np Out_JP1.text = "Ala ma kota"; Rozumiem, że taka operacja nie wpisuje mi ciągu do mojej alokowanej pamięci ale ustawia wewnętrzny wskaźnik struktury na tablicę "Ala ma kota". Czyli w ten sposób utraciłem referencje do tablicy zaalokowanej? Czy da się w takim razie tej tablicy w strukturze używać jak zwykłej tablicy?

Czy zapis

Out_IP1.text[0] = 'a' ;
Out_IP1.text[1] = 'b' ;
Out_IP1.text[2] = 'c' ;
Out_IP1.text[3] = 0x00 ;

oznacza coś innego niż

Out_JP1.text = "abc";

Chodzi mi generalnie o tablice w strukturze alokowana dynamicznie, do której mogę wpisywać sobie co mi przyjdzie do głowy.
Tzn, że na zewnątrz moge używać jej jak zwykłej globalnej tablicy.

0

Nie wiem jak mam traktować zapis np Out_JP1.text = "Ala ma kota"; Rozumiem, że taka operacja nie wpisuje mi ciągu do mojej alokowanej pamięci ale ustawia wewnętrzny wskaźnik struktury na tablicę "Ala ma kota". Czyli w ten sposób utraciłem referencje do tablicy zaalokowanej?
Tak.
Żeby zapisać tekst do zaalokowanej tablicy użyj funkcji strcpy, albo bezpieczniejszego wariantu strcpy_s/strncpy jeśli jest dostępny.

0
  1. Każdy napis jest tablicą (na odwrót nie koniecznie prawda)
  2. Kopiuj napisy za pomocą strcpy
  3. Kopiuj tablice za pomocą memcpy
  4. Sama nazwa tablicy jest automatycznie konwertowana na adres jej pierwszego elementu
  5. Przypisanie wskaźnikowi innego wskaźnika nie kopiuje zawartości tablicy tylko zmienia ten wskaźnik.
0

No ok, ale czy to będzie strcpy czy po prostu zapisze to w ten sposób

Out_JP1.text[0] = 'a';
Out_JP1.text[1] = 'b';
Out_JP1.text[2] = 'c';
Out_JP1.text[3] = 0x00;
Out_JP2.text[0] = '1';
Out_JP2.text[1] = '2';
Out_JP2.text[2] = '3';
Out_JP2.text[3] = 0x00;

to będzie jedno i to samo. Mi chodzi o to, jak teraz powrócić do pierwszego elementu tablicy bo coś takiego nadal nie działa

Out_JP1.text = &Out_JP1.text[0];
Out_JP2.text = &Out_JP2.text[0];

a coś takiego już tak

Out_JP1.text -= 3;
Out_JP2.text -= 3;

Jak powracać do zerowego elementu niezależnie od przesunięcia w funkcji podrzędnej?

0

to będzie jedno i to samo.
w działaniu - tak.
ale po co miałbyś wypełniać poszczególne literki indeksami? jest funkcja do tego, i nazywa się strcpy. rzeczywiście, robi ona to co podałeś: dobrze że rozumiesz ideę, ale nie pisz tak kodu.

Jak powracać do zerowego elementu niezależnie od przesunięcia w funkcji podrzędnej?
Ale po co miałbyś „uszkadzać” wskaźnik zawarty w strukturze? Zostaw go w spokoju, a operuj na kopii wskaźnika.
Skoro alokujesz pamięć ręcznie, to nie zmieniaj wartości tego wskaźnika, bo będzie potrzebna do zwolnienia pamięci.

coś takiego nadal nie działa
Out_JP1.text = &Out_JP1.text[0];

na tej samej zasadzie, co nie działa coś takiego:

x = y;
y = x;

i zastanów się dlaczego.

0

Ok czyli poprawcie mnie jeśli źle rozumuję:

zapis x = tab[i] jest równoważny x = *(tab + i);

Jako argument do mojej funkcji przekazuje sobie strukturę, która ma pole char* wsk.
Wskaźnik ten wskazuje na początek mojej zaalokowanej tablicy

wsk = (char*) calloc(rozmiar, sizeof(char));

W funkcji tej wykonuje np operację

char x[20] = {0};
for(int i=0; i<10; i++)
   x[i] = *str->wsk++;

w tym miejscu kończę funkcję, mój wskaźnik w strukturze pokazuje w tej chwili na str.wsk[10].
Problem dotyczy tega jak sprawić by ponownie pokazywał na str.wsk[0];

Jeśli w funkcji wykonam takie operacje:

char x[20] = {0};
for(int i=0; i<10; i++)
   x[i] = str->wsk[i];

To nie ma problemu ponieważ po wyjściu z funkcji wskaźnik nada pokazuje na str.wsk[0];

Jaka jest różnica pomiędzy tymi zapisami? Gdzie tkwi sedno sprawy do zrozumienia tego zagadnienia?

0

W pierwszym przypadku psujesz str->wsk.
Czyli nie dasz rady jeszcze raz wykonać tej funkcji oraz nie dasz rady poprawnie zwolnić.

0

Nie wiem co masz na myśli mówiąc "psujesz" ponieważ wykonanie operacji
str->wsk - 10; powoduje, że ustawię się na pozycji 0. Wskaźnik nadal pokazuje na tą tablicę tylko na inne jej miejsce. Ale rozumiem, że chodzi CI o to, że nigdzie nie jest zapisany wskaźnik na element 0 tablicy. Idąc tym tropem, kiedy używamy str->wsk[i] i w taki sposób poruszamy się po tablicy to znaczy, że w tej sytuacji niejawnie jest tworzona kopia tego wskaźnika i pracujemy na kopii, a "oryginalny" wskaźnik jest nienaruszony?

0

nie wolno ci zrobić wsk++, bo psujesz wskaźnik, który trzeba przecież zwolnić za pomocą free().

wsk = calloc(...);
char *p = wsk;
// tutaj możesz sobie do woli operować na p, np. robiąc p++

// kiedy skończysz, zwalniasz przydzieloną pamięć
free(wsk);

str->wsk - 10; powoduje, że ustawię się na pozycji 0. Wskaźnik nadal pokazuje na tą tablicę tylko na inne jej miejsce.
nie, wskaźnik wsk nie zmienił wartości. samo użycie wyrażenia x+1 nie powoduje zmiany wartości x mimo że wyrażenie to ma inną wartość niż x.

Musisz nauczyć się odróżniać wyrażenia, które przedstawiają sobą określoną wartość ale nie zmieniają zawartości zmiennych, od instrukcji, które mają na celu przypisanie nowej wartości do zmiennej.

x+1 — to ma wartość różną od x, ale nie zmienia wartości x
x++ — to zmienia wartość x

0

Dziękuje, problem rozwiązany.

Generalnie teraz znam dwie możliwości. Albo poruszanie się po tablicy w sposób: str->wsk[i], takie odniesienie do pozycji w tablicy nie zmienia wskaźnika zaalokowanej pamięci, który nadal pokazuje na element zerowy.

Inna metoda to utworzenie drugiego wskaźnika który pokazuje na to samo miejsce co wskaźnik zaalokowanej tablicy.
Czyli tworzymy str->wsk = (char*) calloc(x, sizeof(char)), a później tworzymy char* str->pWsk = str->wsk;
W tej chwili można wykonywać dowolne operacje na str->pWsk i w dowolnej chwili wrócić na początek tablicy, gdyż adres początku przechowywany jest w str->wsk; Nie ma tez problemu ze zwolnieniem pamięci.

0

To

char* str->pWsk = str->wsk;

są jakieś brednie, nawet się nie skompiluje.
Pewnie miałeś na myśli to:

char *wsk=str->wsk;

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