Użycie pojedynczego wskaźnika, zamiast tablicy wskaźników

0

Część,
borykam się z problemem, którego do końca nie rozumiem, a mianowicie program mnie informuje o tym, że używam zmiennej, która nie jest zainicjalizowana, co nie jest prawdą z mojego punktu widzenia, zatem czegoś nie widzę. Błąd, który mi wyskakuje: 'time' may be used uninitialized in this function [-Wmaybe-uninitialized] .
Używam time, jako wskaźnika będącego tablicą char, zmieniam go w funkcji Clock i Clock_background, które działają poprawnie. Bardzo dziwne mi się wydaje to, że gdy wyświetlam dane przy pomocy funkcji Clock to wszystko dziala, problem zaczyna się, gdy zamierzam to zrobić na zewnątrz funkcji ( LCD_Text(time) w case ). Podejrzewałem początkowo, że zmienna jest zapisywana lokalnie, jednak funkcja Clock_background neguje moje podejrzenie, wyświetlacz pokazuje poprawnie wszystko, gdy przełączę na inny tryb mój komputer. Zmienna nie tylko jest zapisywana w pamięci, ale także zmieniana. Nie mam zatem pojęcia, dlaczego w funkcji Clock, gdy każę mojemu wyświetlaczowi wyświetlić stringa char'ów, to wszystko działa, a gdy poza nią, to nie działa. Obwiniałbym źle zainicjalizowany wskaźnik time.

Kod, który jest (moim zdaniem) istotny:

// Function prototypes

void LCD_Text(char*);                         // funkcja wyświetla cały tekst na wyświetlaczu LCD
void Show_Distance(float);                                  //wyświetla dystans
void Show_Timer(char*);                                  //wyświetla stoper
void Show_Clock(char*);                                  //wyświetla zegar
void Show_Speed(float);                                  //wyświetla predkosc
void Stoper();
void Clock(unsigned char*, unsigned char*, unsigned char*, char*);
void Clock2(unsigned char*, unsigned char*, unsigned char*);
void Clock_background(unsigned char*, unsigned char*, unsigned char*, char*);
// Defining parameters
	unsigned char hour = 0, *p_hour;
	unsigned char minute = 0, *p_minute;
	unsigned char second = 0, *p_second;
	p_hour = &hour;
	p_minute = &minute;
	p_second = &second;
	
	char *time;
	float distance = 0;
	float speed = 0;
while (1) 
	{
		LCD_Command(0x01);  // czyszczenie ekranu
		switch(function_number){
			case 0:
				Show_Distance(distance);
				Clock_background(p_hour, p_minute, p_second, time);
				break;
			case 1:
				//Show_Timer(time);
				//Stoper();
				Clock(p_hour, p_minute, p_second, time);
				//Show_Clock(time);
				//LCD_Text(time);												// Dlaczego to generuje krzaki????
				_delay_ms(500);
				break;
			case 2:
				//Show_Timer(timer_value);
				LCD_Text(time);
				Clock_background(p_hour, p_minute, p_second, time);
				break;
			//case 3:														// Settings?
				
		}
void Clock(unsigned char *hour, unsigned char *minute, unsigned char *second, char *time) {
	unsigned char size_of_char = sizeof(char);
	char time_value[size_of_char*14];
		
	//LCD_Command(0x01);
	/*
	//Kwestia estetyki, nie jest to konieczne
	if (*hour < 10) {
		if (*minute < 10) {
			if (*second < 10) { sprintf(time_value, "Time: 0%d:0%d:0%d", *hour, *minute, *second); }
			else { sprintf(time_value, "Time: 0%d:0%d:%d", *hour, *minute, *second); }
		}
		else {
			if (*second < 10) { sprintf(time_value, "Time: 0%d:%d:0%d", *hour, *minute, *second); }
			else { sprintf(time_value, "Time: 0%d:%d:%d", *hour, *minute, *second); }
		}
	}
	else {
		if (*minute < 10) {
			if (*second < 10) { sprintf(time_value, "Time: %d:0%d:0%d", *hour, *minute, *second); }
			else { sprintf(time_value, "Time: %d:0%d:%d", *hour, *minute, *second); }
		}
		
		else {
			if (*second < 10) { sprintf(time_value, "Time: %d:%d:0%d", *hour, *minute, *second); }
			else { sprintf(time_value, "Time: %d:%d:%d", *hour, *minute, *second); }
		}
	}*/
	sprintf(time_value, "Time: %d:%d:%d", *hour, *minute, *second);
	time = time_value;
	LCD_Text(time);
	_delay_ms(500);
	//_delay_ms(1000);
	(*second)++;
		
	if ((*second % 60 == 0)&&(*second != 0)) {
		*second = 0;
		(*minute)++;																// w nawiasach, żeby nie zdublowała się wartość zmiennej
	}
	else {}

	if ((*minute % 60 == 0)&&(*minute != 0)) {
		*minute = 0;
		(*hour)++;																   // w nawiasach, żeby nie zdublowała się wartość zmiennej
	}
	else {}

	if ((*hour % 24 == 0)&&(*hour != 0))
		*hour = 0;
	else {}
}

To co prawda nie jest jedyny problem tego programu, ale póki co najważniejszy. Byłbym wdzięczny za pomoc.

1

Nie działa bo do time przypisujesz wskaźnik na pamięć lokalną dla funkcji Clock. Taki zapis

time = time_value;

Nie spowoduje, że skopiujesz zawartość time_value do time, tylko przypiszesz wskaźnik. Jak wyjdziesz z Clock to pamięć jest zwolniona i wskaźnik nie pokazuje już na nic konkretnego. Możesz to naprawić alokując pamęć na stercie

// char time_value[size_of_char*14]; // zamiast tego
char *time_value = (char *)malloc(size_of_char*14); // napisz tak

Tylko pamiętaj, że jesteś wtedy odpowiedzialny za zwolnienie tej pamięc poza funkcją Clock.

0
several napisał(a):

Nie działa bo do time przypisujesz wskaźnik na pamięć lokalną dla funkcji Clock. Taki zapis

time = time_value;

Nie spowoduje, że skopiujesz zawartość time_value do time, tylko przypiszesz wskaźnik. Jak wyjdziesz z Clock to pamięć jest zwolniona i wskaźnik nie pokazuje już na nic konkretnego. Możesz to naprawić alokując pamęć na stercie

// char time_value[size_of_char*14]; // zamiast tego
char *time_value = (char *)malloc(size_of_char*14); // napisz tak

Tylko pamiętaj, że jesteś wtedy odpowiedzialny za zwolnienie tej pamięc poza funkcją Clock.

Jak poprawnie powinienem to zapisać?

0

Jak poprawnie powinienem to zapisać?

Ale co poprawnie zapisać? Przecież już Ci napisałem jak naprawić błąd.

0
several napisał(a):

Jak poprawnie powinienem to zapisać?

Ale co poprawnie zapisać? Przecież już Ci napisałem jak naprawić błąd.

jakoś chyba między edycjami to zapisałem, albo strona mi się nie zdążyła odświeżyć, bo ja nie widziałem fixu w kodzie xD

Kurcze, zrobiłem tak, jak napisałeś, niestety dalej wyskakuje mi ten błąd :/

unsigned char size_of_char = sizeof(char);
//char time_value[size_of_char*14];
char *time_value = (char *)malloc(size_of_char*14); // napisz tak

(...)

sprintf(time_value, "Time: %d:%d:%d", *hour, *minute, *second);
time = time_value;

EDIT:
Właściwie, to nie za bardzo wiem, czym miałoby się to różnić, przekazanie adresów nie naprawia błędu, przekazanie wartości w formie *time = *time_value też :/

Wyświetlacz 2x16 zdaje się potwierdzać moją narrację. Nic się nie wyświetla, gdy zakomentuję w funkcji Clock wyświetlanie.

1

przekazanie wartości w formie *time = *time_value też

W ten sposób wykonałbyś skopiowanie tylko jednego elementu, a nie całej tablicy. Bez urazy, ale dlaczego nie poczytasz najpierw trochę o ręcznej obsłudze pamięci zanim zaczniesz jej używać? Poniżej działający przykład na którym możesz się wzorować, nie napisałem wszystkich szczegółów wcześniej, ale sam rozumiesz, jest pierwsza w nocy

inline void init(char **arg)
{
   char *tmp = (char*)malloc(sizeof(char) * 5);
   tmp[0] = 'a';
   tmp[1] = 'b';
   tmp[2] = 'c';
   tmp[3] = 'd';
   tmp[4] = 'e';
   
   *arg = tmp;
}

int main()
{
   char *ptr;
   init(&ptr);
   
   int i=0;
   for(;i<5;++i)
     std::cout << ptr[i] << " ";

   free(ptr);
}

Ten std::cout jest z C++ ofcourse, nie używaj go w C.

0
several napisał(a):

przekazanie wartości w formie *time = *time_value też

W ten sposób wykonałbyś skopiowanie tylko jednego elementu, a nie całej tablicy. Bez urazy, ale dlaczego nie poczytasz najpierw trochę o ręcznej obsłudze pamięci zanim zaczniesz jej używać? Poniżej działający przykład na którym możesz się wzorować, nie napisałem wszystkich szczegółów wcześniej, ale sam rozumiesz, jest pierwsza w nocy

inline void init(char **arg)
{
   char *tmp = (char*)malloc(sizeof(char) * 5);
   tmp[0] = 'a';
   tmp[1] = 'b';
   tmp[2] = 'c';
   tmp[3] = 'd';
   tmp[4] = 'e';
   
   *arg = tmp;
}

int main()
{
   char *ptr;
   init(&ptr);
   
   int i=0;
   for(;i<5;++i)
     std::cout << ptr[i] << " ";

   free(ptr);
}

Ten std::cout jest z C++ ofcourse, nie używaj go w C.

Słusznie, zapomniałem, że daję mu tylko wskaźnik na pierwszy element (przyzwyczajenie z pythona :P chciałem osiągnąć postać string = "text" ), w takim razie nie mam pojęcia, dlaczego to wcześniej działało w samej funkcji, ale whatever. Rozumiem, że mam przekazać te adresy przy pomocy pętli? EDIT Użycie pętli nic nie daje, chyba źle zinterpretowałem to, co miałeś na myśli.

for(int i = 0; i != 13; i++)
		time[i] = time_value[i];

Mógłbyś mi wytłumaczyć, dlaczego nie wystarczy sprintf(time, "Time: %d:%d:%d", *hour, *minute, *second); ?
To działa podobnie, jak powyższe rozwiązanie, postanowiłem przekazywać przy pomocy stringa time_value, ponieważ takie przypisanie sprintf'a nie dawało żadnych rezultatów.

0

dlaczego to wcześniej działało w samej funkcji, ale whatever

Napisałem Ci dlaczego w pierwszym poscie.

Rozumiem, że mam przekazać te adresy przy pomocy pętli?

Nie. Masz je przekazać tak jak Ci pokazałem w uproszczonym przykładzie z mainem. Jeżeli nie potrafisz ułożyć wszystkiego co napisałem w jedną całość to niestety nie potrafię Ci pomóc.

0

Udało mi się usunąć problem, dla potomnych zapiszę rozwiązanie :)

Na początku zastanawiałem się, jak to jest, że w samej funkcji Clock wyświetlają się zmienne, a poza nią nie. Wynika to z tego, że tablica time była zapisywana lokalnie, ale zmienne się zmieniały, ze względu na to, że same zmienne przechowujące wartości godzin, minut i sekund były zapisane przy pomocy wskaźników (człowiek coś na początku pomyśli, a potem zapomni o tym ;D )

Problem leży w char *time;, który jest wskaźnikiem, a ja de facto potrzebuję tablicy wskaźników. Jednak, tablica jest sama w sobie wskaźnikiem (do pierwszego elementu) i to był mój problem, z którym musiałem się przespać, żeby go zrozumieć. Musimy zatem zrobić tablicę wskaźników, jeśli chcemy korzystać z takiego rozwiązania, jakie ja postanowiłem zaimplementować:

char *time[15];                                 // pamiętajmy o tym, że znak /0 też musi być uwzględniony w rozmiarze tablicy! (ja o tym zapomniałem)

Mając tablicę wskaźników, trzeba zmodyfikować prototypy i zmienne wejściowe dla funkcji:

void Clock(unsigned char*, unsigned char*, unsigned char*, char**);
void Clock_background(unsigned char*, unsigned char*, unsigned char*, char**);

W tej chwili, jestem w stanie zaimplementować to w takiej postaci, w jakiej chciałem początkowo, czyli tablicy time użyć od razu w funkcji sprintf. Te wyrażenia warunkowe dodałem, żeby godziny, minuty i sekundy były wyświetlane zawsze w postaci dwucyfrowej, jednak rozwiązanie jest cały czas takie, jakie było na początku, czyli: sprintf(*time, "Time: %d:%d:%d", *hour, *minute, *second);.

void Clock(unsigned char *hour, unsigned char *minute, unsigned char *second, char **time) {
		
	
	//Kwestia estetyki, nie jest to konieczne
	if (*hour < 10) {
		if (*minute < 10) {
			if (*second < 10) { sprintf(*time, "Time: 0%d:0%d:0%d", *hour, *minute, *second); }
			else { sprintf(*time, "Time: 0%d:0%d:%d", *hour, *minute, *second); }
		}
		else {
			if (*second < 10) { sprintf(*time, "Time: 0%d:%d:0%d", *hour, *minute, *second); }
			else { sprintf(*time, "Time: 0%d:%d:%d", *hour, *minute, *second); }
		}
	}
	else {
		if (*minute < 10) {
			if (*second < 10) { sprintf(*time, "Time: %d:0%d:0%d", *hour, *minute, *second); }
			else { sprintf(*time, "Time: %d:0%d:%d", *hour, *minute, *second); }
		}
		
		else {
			if (*second < 10) { sprintf(*time, "Time: %d:%d:0%d", *hour, *minute, *second); }
			else { sprintf(*time, "Time: %d:%d:%d", *hour, *minute, *second); }
		}
	}
	_delay_ms(50);	/* debug */
	(*second)++;
		
	if ((*second % 60 == 0)&&(*second != 0)) {
		*second = 0;
		(*minute)++;																// w nawiasach, żeby nie zdublowała się wartość zmiennej
	}
	else {}

	if ((*minute % 60 == 0)&&(*minute != 0)) {
		*minute = 0;
		(*hour)++;																   // w nawiasach, żeby nie zdublowała się wartość zmiennej
	}
	else {}

	if ((*hour % 24 == 0)&&(*hour != 0))
		*hour = 0;
	else {}
}

Tak na marginesie, wydaje mi się, że teraz w ogóle nie jest mi potrzebna funkcja Clock_background, bo jej rolę teraz spełnia funkcja Clock. Nie chcę być tylko nadgorliwy, muszę sobie wszystko ułożyć w głowie, jak to złożyć do kupy.

W switchu wygląda to tak:

case 1:
				Clock(p_hour, p_minute, p_second, time);
				Show_Clock(*time);
				_delay_ms(500);                                 // to wszystko jest właściwie szkicem, potem zrobię inaczej, żeby to wszystko ładnie działało z przerwaniami
				break;

I wszystko pięknie działa :D

Początkowe przypisanie w postaci time = time_value jest paskudnym przyzwyczajeniem z pythona, ale tak to jest, jak kiedyś się pisało w C, coś tam się niby pamięta, ale potem trzeba dochodzić to wielu, niekiedy banalnych, rzeczy samemu :D

Samemu @several bardzo dziękuje za pomoc w znalezieniu błędu, chociaż on (błąd :P) był tam, gdzie początkowo zakładałem, to czasem rozmowa z drugą osobą przydaje się do ułożenia sobie problemu w głowie :)
Tak między nami, stworzenie tablicy dynamicznej time_value w funkcji Clock nic nie dawało, robiłeś tak na prawdę to samo, co ja robiłem tablicą statyczną. Wydaje mi się, że ja źle przedstawiłem problem, z którym się borykałem, a Ty poszedłeś moim początkowym tropem, co akurat nie dawało rezultatów z powodów, które wytłumaczyłem wyżej (zmienną cały czas zmieniałem lokalnie).

Pozdrawiam wszystkich i życzę miłego dnia :)

PS @kq jeśli miałbyś możliwość, to prosiłbym o zmianę tytułu tematu na "<to co było> Użycie pojedynczego wskaźnika, zamiast tablicy wskaźników"

0

WTF jakim cudem to działa? To Twoje jedyne zmiany? Czym to kompilujesz? Jeśli to jedyne co zrobiłeś i nie masz żadnego malloc nigdzie to masz murowany Segmentation Fault.

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