Pointer değişkene değer atama hatası

Başlatan Jey@Nfer, 20 Mayıs 2011 - 23:19:17

« önceki - sonraki »

0 Üyeler ve 2 Ziyaretçi konuyu incelemekte.

Jey@Nfer

Arkadaşlar işaretçilerle başım gerçekten dertte ..
Normal basit bir program yazarken bile karışma garip hatalar çıkıyor kafayı yicem ya.. Uzatmadan sorunu anlatayım..

Arkadaşlar birden çok işeretçi değişkenim var ve bunların her birine ayrı değer atamak istiyorum..
scanf() fonksiyonuyla değişkenin içeriğine direk atama yapamayacağım için ben de bir integer değişken alıp işaretçi değişkenlerden birine değer ataması yapmam gerektiğinde o integer değişkeni scanf ile okutup pointerın içeriğine eşitleyererk çözeyim dedim..
Ama ne yazık ki ilk değişkene değer ataması yapıldıktan sonra bir türlü diğerleine atanma yapılmıyor..

Durumu kodlar üzerinden anlatayım..



#include "stdio.h"

main()
{
    int sayi1, sayi2;

    int *s1, *s2, *s3, *s4, *s5;


    printf("sayi1 i giriniz..\n");
    scanf("%d",&sayi1);

    *s1=sayi1; // 1- sayi1 değişkeninin içeriğini s1 işaretçisinin İÇERİĞİNE aktarır

    printf("sayi2yi giriniz...\n");
    scanf("%d",&sayi1);

    *s2=sayi1; // 2- sayi1 değişkeninin değerini s2 işaretçisinin İÇERİĞİNE aktarır

    printf("sayi3u giriniz \n");
    scanf("%d",&s3); //3- s3 işaretçisine adres ataması yapar. Yani s3 işaretçisinin işaret ettiği adres artık buradan girilen değerdir


    *s4=*s1;
    *s1=*s2; //4- s1 ve s2 işaretçilerinin içerikleri yer değiştiriyior
    *s2=*s4;

    *s5= 77; //5- s5 işaretçisini içeriği 77 yapılıyor

    sayi2=*s4; //6- sayi2ye s4ün içeriği atanıyor

    s5=&sayi2; //7- sayi2nin adresi sayi5e adres bilgisi olarak veriliyor

    printf("sayi1 degeri : %d \n", sayi1);
    printf("sayi2 degeri : %d \n", sayi2);
    printf("s1 degeri : %d \n", *s1);
    printf("s2 degeri : %d \n", s2); //8- bu gösterim yanlış... s2nin adres bilgisini integer olarak gösterir
    printf("s3 dgeri1 : %d \n", s3); // 9- (3)te girilen değeri gösterir.. ama aslında adres bilgisidir..
    printf("s3 dgeri2 : %d \n", *s3); //10-  burda hata vermesi gerekir.. (3)teki adresin içeriğini gösterir
    printf("s4 degeri : %d \n", *s4);
    printf("s5 degeri : %d \n", *s5); //11- s5 degeri : 77

    printf("sayi1 adres : %p \n", &sayi1);
    printf("sayi2 adres : %p \n", &sayi2);
    printf("s1 adres : %p \n", s1);
    printf("s2 adres : %p \n", s2);
    printf("s3 adres : %p \n", s3);// 12- (3)teki girilen adres bilgisini gösterMEZ.. s3ün hafızada bulunduğu adresi gösterir
    printf("s4 adres : %p \n", s4);
    printf("s5 adres : %p \n", s5);//13- (7)de atanan sayi2nin adresini gösterir


    printf("\n\n");

}



Açıklama alanlarını  "// Numara- " şeklinde numaralandırdım.. acaba yanlış nerde? gerçi nerede olduğunun biliyorum da.. nasıl çözerim?

(2) numaralı alanda atama yapılamıyor.. (1)de olan şey (2)de niye çalışmaz anlamadım gitti..

(4) , (5) ve (6) numaralı kısımlarda da aynı şekilde hata veriyor ;  *pointer=deger olması gerekmiyor mu? niye çalışmıyor?

Gerçekten kafam karmakarışık halde 2 gündür uykusuzum bu ödevi bitirmem lazım yardımcı olursanız çok sevinicem.. Nerde hata var..
niye çalışmıyor bu ya...

Not: ayrıca bunlar başka bir fonksiyonda değil main fonksiyonunda olması gerekiyor... yani başka bir fonksiyona alınca çözebiliyorum.. Gerçi o ayrı bir muamma.... Başka fonksiyonda aynı kodları koyunca çalışıyor, main fonksiyonunda bu haldeyken çalışmıyor..
Bir de (7)de olduğu gibi pointer=&isaretci yapmak istemiyorum.. o zaman işaretçi sayısı kadar değişken lazım ekstradan çünkü ben işaretçinin içerik bilgisini sabit kalmasının istiyorum...

özet : main() fonksiyonunda *pointer=isaretci eşitlemesi niye çalışmıyor?


Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 20 Mayıs 2011 - 23:32:57

bakın böyle çalışıyor:


#include <stdio.h>

void referans_swap(int* , int*);/*"referans ile çağırma"(call­by­reference)*/
int main(void)
{
int data1=5;
int data2=49;
int *data1_ptr=&data1;
int *data2_ptr=&data2;

referans_swap(&data1, &data2);
printf("referans_swap tekrar cagirildiktan sonra bellekteki orjinal veriler:\n");
printf("\t data1 = %d \t data2= %d \n\n",*data1_ptr,*data2_ptr);
return 0;
}

void referans_swap(int* a_ptr, int* b_ptr)
{
int gecici;
gecici=*a_ptr;
*a_ptr=*b_ptr;
*b_ptr=gecici;
return;
}



ama böyle çalışmıyor:



#include <stdio.h>

int main(void)
{
int *data1;
int *data2;
int gecici;

*data1=5;
*data2=49;

gecici=*data1;
*data1=*data2;
*data1=gecici;

printf("main fonksiyonu içindeki orjinal veriler:\n");
printf("\t data1 = %d \t data2= %d \n\n",*data1,*data2);

}



niye hocam bi yardımcı olun ya.. main fonksiyonunun neyi var?
Hırs , azim , tevekkül ...

www.mehmetvahit.net

egcodes

Temel bir bilgi vereyim tekrar gözden geçir istersen.

int *p;

bu değişken adres tutmakla görevli ve hayata geldiği anda içindeki değer çöp değer(yani rastgele bir değer)'dir. *p yaparak o çöp değer adresinin gösterdiği yerdeki değere ulaşıyoruz bu işlem de zaten saçmadır. Senin yaptığın çöp değeriin gösterdiği yere değer atamak.

Hata ordadır.

Kolay gelsin.
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d

Jey@Nfer

#2
teşekkürler egcodes ; peki nasıl çözebilirim ?
Şu anda gerçekten 10larca yöntem denemiş durumdayım.. ama olmuyor... yok..


Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 21 Mayıs 2011 - 10:47:21

eyvallah sonunda kafama dank eden bi yöntemle çözdüm arkadaşlar...

bu hatanın sebebi hafızada o an yer ayrılmamış olması.. başka bir fonksiyona gönderdiğimizde fonksiyona giden veriler için bellek kontrolü yapılıyor ve her biri için yer tahsis ediliyor dolayısıyla üzerinde çalışma yapılabiliyiro..

bu sorunu çözen çok basit olay ise hafızadan dinamik olarak yer istemek; yani o vermiyorsa biz ister alırız:D

nihayetinde sorunu çözen kod parçası:



    s1=(int *) malloc(1*sizeof(int));
    s2=(int *) malloc(1*sizeof(int));
    s3=(int *) malloc(1*sizeof(int));
    s4=(int *) malloc(1*sizeof(int));
    s5=(int *) malloc(1*sizeof(int));



programa bu basit kodları ekleyince çatır çatır çalıştı..

yardımcı olmak isteyen arkadaşlarıma teşekkürler...
Hırs , azim , tevekkül ...

www.mehmetvahit.net

Erdem

#3
Evet ilk hata mesajındaki hata null bir göstergenin gösterdiği adrese değer atamaya çalıştığın için oluyordu. Null bir göstergenin gösterdiği adreste bir şeyler yapmak sistemin herhangi bir şey yapmasına neden olabilir.

Göstergeleri biraz karıştırmışsın galiba. O yüzden açık olsun diye şu örneği yazdım:

#include "stdio.h"

void swap(int * a, int * b)
{
    int gecici = *a;
    *a = *b;
    *b = gecici;
}

int main()
{
    int ilksayi = 12, ikincisayi = 25;
   

    int * ilk = &ilksayi;
    // ilk göstergesi ilksayının adresini tutuyor

    int * ikinci = &ikincisayi;
    // ikinci gösterge de ikincisayının adresini tutuyor

    printf("ilk gostergenin adresi: %p\n", ilk);
    printf("ilk gostergenin gosterdigi ilk sayi: %d\n", *ilk);
    printf("ilk sayinin adresi: %p\n", &ilksayi);

    swap(ilk, ikinci);

    printf("ilk sayinin  sonraki degeri: %d\n", ilksayi);
    printf("ikinci sayinin sonraki degeri: %d\n", ikincisayi);
}


Ama bu yerdeğiştirmenin bir olayı yok. Basitçe bir tamsayıyı başka bir sayıda atamaktan öte bir şey değil. Tek farkı parametre olarak bir gösterge alması..


Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 22 Mayıs 2011 - 02:39:12

Bir de ek olarak gösterdiğin şekilde dinamik olarak bellek ayırdığında free ile geri vermek gerekiyor.Yoksa bellek sızıntısı oluşuyor. Eğer free ile verilmiş bir göstergeye tekrar erişmek istersen bu sefer de serseri gösterge (dangling pointer) oluşuyor. İşte C++ ve D bu konuda C'ye göre avantajlı :)
Eğer Arch Linux tabanlı bir dağıtıma geçmek isterseniz Arcolinux D sürümünü buradan indirebilirsiniz.

Elektronik

sem

Gösterici kullanırken, göstericinin gösterdiği alanın bellekte ayrılmış olduğuna, işiniz bittiğinde de ayrılan belleği verdiğinize daima emin olmanızda fayda var. Yoksa program büyük ihtimalle çalışmayacaktır ya da tesadüfen bir çalışırsa bir sonra yine çalışmayıp kararsızlığa neden olacaktır. Alanı verirken de dikkat etmek gerekiyor. Önceden sisteme verilmiş alanı tekrar boşaltmaya çalışırsanız stack smash diye çok korkutucu görüntüsü olan (stack alanını gösteren) bir hata ile karşılaşırsınız... Allah muhafaza...

Ya da static bir alanı geri bırakmaya çalışırsanız aynı şekilde stack bölümünü ekranda göreceksiniz .. static değişkenlerin tuttuğu alanı sisteme geri iade etmemeniz gerekiyor...

static değişkenin bırakılması ve korkunç hataya bir örnek =)

#include <stdio.h>
#include <malloc.h>

void fonk(void)
{
char *user  = (char *)getenv("USER");
puts(user);
free(user);
}


int main()
{
fprintf(stdout, "Akış buraya gelecek.\n");
fonk();
fprintf(stdout, "Akış buraya gelemeyecek\n");

}



Çıktı:
Alıntı YapAkış buraya gelecek.
sem0900

*** glibc detected *** ./dene: munmap_chunk(): invalid pointer: 0xbfe5f82b ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6(+0x6b281)[0xb7728281]
/lib/i686/cmov/libc.so.6(+0x6c4fe)[0xb77294fe]
./dene[0x80484af]
./dene[0x80484e7]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb76d3c76]
./dene[0x80483f1]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:03 1582444    /home/sem0900/dene
08049000-0804a000 rw-p 00000000 08:03 1582444    /home/sem0900/dene
09188000-091a9000 rw-p 00000000 00:00 0          [heap]
b768c000-b76a9000 r-xp 00000000 08:03 1310723    /lib/libgcc_s.so.1
b76a9000-b76aa000 rw-p 0001c000 08:03 1310723    /lib/libgcc_s.so.1
b76bc000-b76bd000 rw-p 00000000 00:00 0
b76bd000-b77fd000 r-xp 00000000 08:03 1314345    /lib/i686/cmov/libc-2.11.2.so
b77fd000-b77ff000 r--p 0013f000 08:03 1314345    /lib/i686/cmov/libc-2.11.2.so
b77ff000-b7800000 rw-p 00141000 08:03 1314345    /lib/i686/cmov/libc-2.11.2.so
b7800000-b7803000 rw-p 00000000 00:00 0
b7814000-b7817000 rw-p 00000000 00:00 0
b7817000-b7818000 r-xp 00000000 00:00 0          [vdso]
b7818000-b7833000 r-xp 00000000 08:03 1310745    /lib/ld-2.11.2.so
b7833000-b7834000 r--p 0001a000 08:03 1310745    /lib/ld-2.11.2.so
b7834000-b7835000 rw-p 0001b000 08:03 1310745    /lib/ld-2.11.2.so
bfe4b000-bfe60000 rw-p 00000000 00:00 0          [stack]
Aborted

sem0900'dan sonra çöktü program... Tabii kod çok küçük olduğu iççin çok korkutucu olmadı çıktı =)
".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?

Jey@Nfer

#5
Erdem teşekkürler.. oradaki kodlar sadece örnek olması için zaten ya... 300 satırlık bütün programı koymaktansa hatalı olan kısımların tamamına birer örnek verdim:D

sem0900: malloc.h kütüphanesiyle hiç çalışmadım google amcaya merak edip sordum bi dinamik hafızayla alakalı detaylı bi kütüphaneymiş baya...  gelecek programarda kullanıcam.. ;)
ayrıca ben bu kodu derleyince o korkutucu satırlar yerine sadece hevesimi kaçıran oldukça basit bir "Parçalama Arızası" yazısıyla karşılaşıyorum... Bu parçalama arızasını nasıl sendeki gibi detaylı hale getirebilirim??
Hırs , azim , tevekkül ...

www.mehmetvahit.net

sem

C ile uğraşacaksınız malloc.h başlığını emin olun ki mutlaka kullanacaksınız daha doğrusu zorunda kalacaksınız =) Muhtemelen malloc, calloc ve free üçlüsü en çok kullandığınız fonksiyonlar olacak =)

Sizde parçalanma hatası (segmantation fault) vermiş program. Enteresan bir durum. Normalde bu hatayı daima stack ile alakalı sanıyordum, bende hep aynı sonuç dönüyor çünkü.

Bu hata çıktısını ben detaylandırmadım. Stack taşması ile parçalanma hatası; ikisi de bellek yönetimi ile ilgili fakat tam olarak aynı diyemeyiz. Parçalanma hatası daha çok program için ayrılmamış olan bellek bölgelerine erişmeye çalıştığımızda ortaya çıkıyor.

#include <stdio.h>

int main()
{
char *pointer;

pointer = 'a';

}


Örneğin yukarıda pointer göstericisinin gösterdiği adres program için ayrılmamış. O nedenle bu program segmantation fault döndürecektir. Çözüm olarak free ile yer ayırma ya da ilk değer verme gibi yöntemler kullanılabilir. Yukarıdaki programı aşağıdaki gibi yazarsak sorun olmaz;

#include <stdio.h>

int main()
{
char *pointer = 'a';

}


Çünkü ilk değer atayarak oluşturduğumuz için, adresi de belli.


Bunlar gibi parçalanma (segmantation fault) hatalarında program sistem tarafından SIGSEGV sinyali gönderilecek sonlandırılır.

Stack hataları ile daha çok programa ait olmayan alan sisteme geri verilmeye çalışıştığımda ya da boşaltılmaması gereken alanları boşaltığımda; yani örneğin bir göstericiye iki kere free uyguladığımda ya da static bir alanı geri verdiğimde gibi durumlarda karşılaşıyorum.

Aslında genel olarak bakıldığında bunlar da bellek hataları tabii. Fakat sistem tarafından da gördüğü işlem biraz daha farklı demek ki. Çünkü parçalanma hatalarında sistem SIGSEGV gönderirken stack hatalarında SIGABRT (abort) göndererek programı sonlandırıyor.


Kısaca söylemek gerekirse =) Korkunç dediğim çıktıdaki gibi belleği görebileceğiniz şekilde programı test etmek için Debug işlemi yapabilen bir IDE kullanmak daha iyi olacaktır. Yoksa parçalanma hatasında programa ait bellekleri (stack, heap) derleyiciye nasıl gösterebiliriz, bilmiyorum.
".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?

Jey@Nfer

@sem0900 teşekkürler... ben codeblocks kullanıyorum , klasik bi hata çıktısı var başkasını döndürmez zaten.. ne olsa "Segmentation Fault", şimdiye kadar başka bi hata çıktısı almadım hiç:D sen ne kullanıyorsun bu arada gcc ile de derledim o da aynı şekilde parçalama arızası diyor sadece..
derlemiyor zaten "pointer hafızasıyla kopyalamaya çalıştıpınız alan farklı" şeklinde çevirebileceğim basit bi hata çıktısı veriyor.. şöyle hangi hafıza birmine ne yapmaya çalışırken hata olduğunu detaylı gösteren bi IDE bulsam iyi olcak sanırım:D
Hırs , azim , tevekkül ...

www.mehmetvahit.net

egcodes

Bildiğim kadarıyla çıktıyı IDE vermez. GCC derleyicisi ile derlerseniz hatayı gcc derleyicisi verir yani çıktıyı, IDE'de bunu alıp size gösterir.
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d

sem

Ben de öyle biliyorum. IDE,  derleyici, debugger (ayıklayıcı mıdır artık Türkçesini kesemedim) gibi birimleri ortak çatıda toplayarak kod yazmamımızı kolaylaştıran birimler olarak biliyorum ben de.

Daha ayrıntı çıktı görmek için GCC nin -Wall parametresi kullanılabilir fakat yine istediğiniz şekilde segmantation fault yerine program belleğini dökmeyecektir.
".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?

Erdem

Alıntı yapılan: sem0900 - 23 Mayıs 2011 - 00:16:24
#include <stdio.h>

int main()
{
char *pointer;

pointer = 'a';

}


Örneğin yukarıda pointer göstericisinin gösterdiği adres program için ayrılmamış. O nedenle bu program segmantation fault döndürecektir.

Burada segmentation fault döndürmüyor aslında. Derleyici sadece uyarı mesajı veriyor.

"warning: assignment makes integer from pointer without a cast" */

Bunun nedeni de ikinci ifadede pointer'ın türünün char* olması diğer tarafın da tamsayı (integral) türünde olması. Burada gösterge dizinin ilk karakterini göstermiş oluyor.
Eğer Arch Linux tabanlı bir dağıtıma geçmek isterseniz Arcolinux D sürümünü buradan indirebilirsiniz.

Elektronik

egcodes

Yukarıdaki kodda zaten bir sentaks hatası yok C kurallarına uygun yazılmış bir koddur.

O yüzden derleyicileri yazanlar yine de programcıların ne olup bittiğini anlaması için warning seçenekleri koymuştur.
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d

sem

egcodes'un dediği gibi kodda sentaks açısından herhangi bir sorun yok. Fakat ben yanlış yere atama yapmışım. Yanlışlık da değil de farklı bir şey anlatıyor o kod. Bir tane * esksik yazmışım o nedenle istediğimi anlatamamışım.

'a' yı tamsayı (integer)  olarak algıladığı için o uyarıyı vermiyor program. Ben adrese atama yapmışım fark etmeden. Atanan tür char fakat atama yapılan yer char * olduğu için uyarıyı veriyor.

*pointer = 'a';  şeklinde başına adres erişim işleci koyup, kodu derleyip çalıştırarak

" Segmantation Fault" yazısını görebilirsiniz.
".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?

Erdem

Alıntı yapılan: sem0900 - 23 Mayıs 2011 - 20:24:55
*pointer = 'a';  şeklinde başına adres erişim işleci koyup, kodu derleyip çalıştırarak

" Segmantation Fault" yazısını görebilirsiniz.

Ama o zaman görmememiz imkansız olurdu  :D Herhangi bir karakteri göstermeyen null bir göstergenin gösterdiği değere atama yapmaya çalışıyoruz. Bilmiyorum anlatmak istediğin bu muydu ama.

Bu çalışıyor.

    char karakter = 'a';
    char * p = &karakter;


Bir de D'de örneğin kaç tane olduğunu bilmediğimiz bir diziyle örneğin ekranın güncellenmesi için kaç milisaniye geçmiş, çizilmesi için kaç milisaniye geçmiş onları hesaplıyorum.

Örneğin atıyorum değerler şu şekilde 8 7 6 7 7 .. Ama kaç tane olduğunu bilmiyoruz. Ve bu programın çalışma süresine göre değişebilir.  Benim yapmak istediğim atıyorum 18 tane değer varsa bunları toplayacak ve ortalamasını verecek. Tek satırda bunu bulabildiğimi söylesem herhalde artık C'yi bırakıp D'ye geçmek isterdiniz :)
Eğer Arch Linux tabanlı bir dağıtıma geçmek isterseniz Arcolinux D sürümünü buradan indirebilirsiniz.

Elektronik

sem

C yi bırakma gibi bir niyetim yok fakat tek satır olması hoşmuş bir sistem programlama dili için özellikle.




char * p = &karakter;

Burada ilk değer vererek oluşturduğunuz için çalışıyor.
".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?