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

Użycie pojedynczego wskaźnika, zamiast tablicy wskaźników
DX
  • Rejestracja:około 6 lat
  • Ostatnio:ponad 3 lata
  • Postów:25
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:

Kopiuj
// 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*);
Kopiuj
// 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;
Kopiuj
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?
				
		}
Kopiuj
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.

edytowany 1x, ostatnio: kq
several
  • Rejestracja:ponad 15 lat
  • Ostatnio:3 minuty
1

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

Kopiuj
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

Kopiuj
// 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.


edytowany 3x, ostatnio: several
DX
  • Rejestracja:około 6 lat
  • Ostatnio:ponad 3 lata
  • Postów:25
0
several napisał(a):

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

Kopiuj
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

Kopiuj
// 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ć?

several
  • Rejestracja:ponad 15 lat
  • Ostatnio:3 minuty
0

Jak poprawnie powinienem to zapisać?

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


DX
  • Rejestracja:około 6 lat
  • Ostatnio:ponad 3 lata
  • Postów:25
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 :/

Kopiuj
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.

edytowany 3x, ostatnio: dark_Xenio
several
  • Rejestracja:ponad 15 lat
  • Ostatnio:3 minuty
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

Kopiuj
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.


edytowany 1x, ostatnio: several
DX
  • Rejestracja:około 6 lat
  • Ostatnio:ponad 3 lata
  • Postów:25
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

Kopiuj
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.

Kopiuj
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.

edytowany 2x, ostatnio: dark_Xenio
several
  • Rejestracja:ponad 15 lat
  • Ostatnio:3 minuty
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.


DX
  • Rejestracja:około 6 lat
  • Ostatnio:ponad 3 lata
  • Postów:25
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ć:

Kopiuj
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:

Kopiuj
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);.

Kopiuj
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:

Kopiuj
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"

edytowany 3x, ostatnio: dark_Xenio
several
  • Rejestracja:ponad 15 lat
  • Ostatnio:3 minuty
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.


edytowany 1x, ostatnio: several
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)