Dlaczego program wyświetla wartość 22134 zamiast 4?

0

Dlaczego po przekazaniu do funkcji wartość jest kompletnie randomowa?

 #include <stdio.h>
#include <stdlib.h>
int g(int *p){
	printf("%d\t%p",*p,p);
}

int main(int argc, char *argv[]) { //%p wyswietla adres
int x;
int *p=&x;
*p=4;
g(&p);
	return 0;
}
4

Bo masz operator & przy wywołaniu g(&p). Wywołaj g(p) i wtedy wyświetli 4.

3

Bo pobrałeś adres wskaźnika, czyli wyszedłeś o jeden poziom pośredniości z daleko. W main masz:
x = 4
p = adres zmiennej x w pamięci (np. 0x1234)
*p = x = 4
&p = adres zmiennej p w pamięci (np. 0x2345)
Wewnątrz funkcji g do zmiennej lokalnej p, nazwijmy ją na chwilę p_fun przypisałeś &p z maina, czyli przypisałęś tam adres zmiennej p (z maina) w pamięci, toteż teraz:
p_fun = &p = adres zmiennej p w pamięci (np. 0x2345)
*p_fun = p = adres zmiennej x w pamięci (np. 0x1234)

Więc jak widzisz spodziewanie się gdzieś wewnatrz funkcji g wartości 4 nie ma sensu, bo ta wartość jest pod **p_fun

0

Moge skorzystać z tego postu i się coś zapytać odnośnie takiej sytuacji :

int x=10;
x=2*x--;
printf("%d",x);
 

dlaczego wartość x to 20
2*10 =20
i teraz nie powinno się zdekrementować x o 1 ? i wyjść x=19

0

Bo masz x--, a nie --x. Gdybyś miał --x to wynik wynosiłby 18, ponieważ 2 * 9 to 18.

0
  1. Po pierwsze nieładnie stosować w jednej linii dwa wyrażenia modyfikujące tą samą zmienną, tak jak np. ++x++
  2. Po drugie skąd wiesz które przypisanie wykona się jako pierwsze?
    x=2*x--;
    oznacza:
x = 2*x
x = x-1

albo:

tmp = 2*x
x = x-1
x = tmp

Bo liczy się tutaj kolejność wykonywania operacji. Logika dyktuje że najpierw wykona się wszystko po stronie prawej, a dopiero na koniec nastąpi przypisanie wartości do x, czyli to co przedstawiłem wyżej jako opcje drugą.

0

W ogóle 19 byłoby gdybyś miał to zapisane tak:

x*=2;
--x;
0

to co w tym zadaniu robi -- ? ta instrukcja nie jest wykonywana?

0
Shalom napisał(a):
tmp = 2*x
x = x-1
x = tmp

Bo liczy się tutaj kolejność wykonywania operacji. Logika dyktuje że najpierw wykona się wszystko po stronie prawej, a dopiero na koniec nastąpi przypisanie wartości do x, czyli to co przedstawiłem wyżej jako opcje drugą.

Jest wykonana, tak jak opisał to Shalom. Do x najpierw przypisujesz x-1, a potem nadpisujesz x wartością 2*x (stare x, sprzed wykonaia x-- czyli 10)

0

@bartek164 ta instrukcja robi:

tmp = i
i = i-1
return tmp

Czyli zwraca starą wartość, ale wartość zmiennej dla której wywołałeś -- zmniejsza się o 1. Więc dla:

int i = 1;
int x = i--;
``
x wynosi 1 (stara wartość dla i), a i wynosi 0 (wartość zmniejszona o 1).
0

Jeszcze jedno :) powiedzmy że mamy taki przykład x=x-- ;
(chyba nie rozumiem jak działa postinkrementacja bo ja myślałem że tak:
temp=x; //tworzy zmienną o takiej samej wartości co x
x=temp; //przypisuje do x wartosć x(nadpisuje)
x=x-1; //zmniejsza wartość x o 1, przecież ta instrukcja powinna się wykonać po średniku x=x--;
Nie rozumiem dlaczego napisałeś że temp to 2*x, przecież ta postin.. odnosi się tylko do x a nie do calego wyrażenia

0
  1. Wybij sobie z głowy dwie operacje na raz które zmieniają tą samą zmienną bo to tylko kłopoty.
  2. A skąd wiesz, geniuszu, która z operacji przypisania wykona się wcześniej? Skąd wiesz ze pierwsze wykona się to twoje x=x a nie x=x-1 z post inkrementacji? Ba, na logikę to właśnie CAŁA prawa strona wykona się wcześniej niż to końcowe przypisanie x=x bo przecież tak sie zwykle wykonuje obliczenia! Jak robisz x=1+2+3+4 to NAJPIERW obliczasz 1+2+3+4 a dopiero NA KONIEC przypisujesz wynik do x. Więc u ciebie może najpierw wykonać się x--, zmniejszając x o 1 ale zwracając starą wartość x a dopiero na koniec wykona się x=x.
0

no ja mówie że od prawej strony :( , tylko najpierw jest tworzona kopia liczby x i potem przypisywane do x (No chodzi mi o to że operacja zmniejszenia x o 1 następuje po wykonaniu instrukcji, po średniku, czyli po przypisaniu x, albo jak w poprzednim przypadku po pomnożeniu x*2 i przypisaniu.

No a jak na przykłąd wywołuje się funkcje np. funkcja(x++); to** zostanie wykonana instrukcja wywołania i wykoana zostanie funkcja, po zakończeniu jej wartość x zwiększy się o 1 (zwiększenie wartośći x nastąpi po zakończeniu funkcji 'funkcja' )**
a w tym przypadku tak nie jest ? dlaczego

0

No chodzi mi o to że operacja zmniejszenia x o 1 następuje po wykonaniu instrukcji, po średniku, czyli po przypisaniu x

Ale dlaczego uważasz że tak jest? Skompiluj to sobie do poziomu asemblera i zobacz co ci kompilator wygenerował. Będziesz miał wszystko ładnie rozbite na osobne instrukcje.

Patrz: https://godbolt.org/g/riy45d

        mov     DWORD PTR [rbp-4], 1
        mov     eax, DWORD PTR [rbp-4]
        lea     edx, [rax-1]
        mov     DWORD PTR [rbp-4], edx
        mov     DWORD PTR [rbp-4], eax

Popatrz co się dzieje:
rbp-4 to nasza zmienna lokalna x

  1. Najpierw wpisujemy sobie do x wartość 1
  2. Potem do eax ładujemy sobie wartość zmiennej x
  3. Potem do edx ładujemy wartość eax-1 czyli x-1
  4. Potem do zmiennej x wpisujemy wartość z edx czyli x-1
  5. Potem do zmiennej x wpisujemy wartość z eax czyli pierwotny x
    cbdo.
0

Mam pytanie, stos jest czyszczony z każdą kolejną instrukcją ?

0

Oczywiście że nie, bo niby czemu? Jakby to miało działać w ogóle? Ty masz pojęcie o czym piszesz? Ramki funkcji są czyszczone podczas wychodzenia ale tylko tyle.

0

no ale jak mamy np.instrukcje dla int x=0 :
x++; //to po wykonaiu tej instrukcji w stosie zostaje 0 natomiast x = 1
printf(x); //no to tutaj ze stosu wypisuje się 0 0_o

2

Na jakim stosie? Matka wie że ćpiesz? x jest zmienną na stosie i w tym kodzie będzie jedyna zmienną na stosie. Kompilator tutaj pewnie w ogóle oleje tą wartość tymczasową po x++ skoro jej nie używasz, a nawet jakbyś używał to trzymałby ją w rejestrze procesora. Printf utworzy nową ramkę stosu wykonania funkcji, ale jest tam jeden argument i może zostać przekazany przez rejestry a nie przez stos. A nawet jeśli przez stos to przecież trafi tam wartość x czyli 1.
Serio, zmień dilera.
Zresztą sprawdźmy!
https://godbolt.org/g/WYqhNY

        mov     DWORD PTR [rbp-4], 1
        add     DWORD PTR [rbp-4], 1
        mov     eax, DWORD PTR [rbp-4]
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf

Jest tak jak mówiłem -> jest jedna zmienna środowiskowa na stosie pod rbp-4. Ten tymczasowy wynik z x++ w ogóle jest olewany bo widać że w kodzie mamy tylko x=1 oraz x=x+1 a potem wywołany jest printf z parametrami w rejestrach esi, edi

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