Dizi uzunluğu belirtilmeyen bir string nasıl tanımlanabilir?

Merhaba arkadaşlar.

C dilini öğrenmeye çalışıyorum. Aşağıdaki kodlarda input fonksiyonu prompt isimli bir pointer’ı argüman olarak alıyor ve prompt'a yazılan string’i, printf fonksiyonuyla ekrana yazdırabiliyorum.

Ancak scanf fonksiyonuna sadece uzunluğu belli olan bir string verisini argüman olarak verebiliyorum.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void f1(int max, int min, int x, int y){
	/*
	min’den max’a kadar olan ve
	x ile y arasında olmayan sayıları
	ekrana yazdıran fonksiyon.
	*/
	int i;
	for(i=min; i < max; i++){
		if(x < i && i < y){
			continue;
		}
		printf("%d\n", i);
	}
	sleep(2);
}

int input(char *prompt){
	/*
	Python'dakine benzer bir input();
	fonksiyonu.
	*/
	char data[10];
	printf("%s", prompt);
	scanf("%s", data);
	return atoi(data);
}

int main(){
	int max = input("Max: ");
	int min = input("Min: ");
	int x = input("x: ");
	int y = input("y: ");
	f1(max, min, x, y);
	return 0;
}

Konuyu stackoverflow’da araştırırken, bir mesajda stringlerin aşağıda gösterildiği gibi yazılamayacağını okumuştum.

int input(char *prompt){
	/*
	Python'dakine benzer bir input();
	fonksiyonu.
	*/
	char *data;
	printf("%s", prompt);
	scanf("%s", data);
	return atoi(data);
}

Merak ettiğim şey şu; bir pointer olmasına rağmen, prompt'u, printf'e argüman olarak verdiğimde bir sorun oluşmazken, yine bir pointer olan data'yı scanf'e neden argüman olarak verdiğimde Parçalama arızası (çekirdek döküldü) şeklinde bir hata alıyorum.

Yani, data'yı yalnızca char data[10]; şeklinde yazarak mı scanf'den dönen veriyi tutmasını sağlayabiliriz?

scanf() yerine gets() kullanabilirsin eğer string alacaksan.

Cevap için teşekkür ederim.

gets()'i şu şekilde kullanabiliyorum.

int input(char *prompt){
	/*
	Python'dakine benzer bir input();
	fonksiyonu.
	*/
	char data[10];
	printf("%s", prompt);
	gets(data);
	return atoi(data);
}

Bahsettiğim şey şununla ilgili:

char data[10], uzunluğu belirtilmiş bir string verisi. char *data ise bir pointer. Ben bu data'yı, tıpkı prompt'u kullandığım gibi kullanamaz mıyım?

Yani aşağıdaki kodlarda prompt bir pointer olmasına rağmen printf fonksiyonuna argüman olarak verdiğimizde, stringin kendisi ekrana yazdırılıyor. Aynı durum neden data için geçerli değil?

int input(char *prompt){
	/*
	Python'dakine benzer bir input();
	fonksiyonu.
	*/
	char *data;
	printf("%s", prompt);
	/*scanf("%s", data);*/
        gets(data);
	return atoi(data);
}

data'yı kullanabilmek için iki yol izleyebiliyorum:

  1. Ya data'yı bir array olarak belirtiyorum:
int input(char *prompt){
	/*
	Python'dakine benzer bir input();
	fonksiyonu.
	*/
	char data[10];
	printf("%s", prompt);
	scanf("%s", data);
	return atoi(data);
}
  1. Ya da bir _data[10] isminde bir array oluşturuyorum ve onu da *data isimli bir pointer’a atıyorum.
int input(char *prompt){
	/*
	Python'dakine benzer bir input();
	fonksiyonu.
	*/
	char _data[10];
	char *data = _data;	
	printf("%s", prompt);
	scanf("%s", data);
	return atoi(data);
}

prompt pointer’ı için herhangi bir array tanımlanmadı ama biz bu pointer’ın string verisini printf ile yazdırabiliyoruz. Aynı durumu data için yapamıyorum, bunun nedenini merak ediyorum.

char *data; olarak tanımladığınızda. data aslında dizini 1. elemanın adresini tutacaktır. Dolayısıyla
scanf("%s", data) yazmak ile scanf("%d", &data[0]) yazmak arasında hiç bir fark yoktur. Bu aslında istemediğimiz bir şeydir. Çünkü bir string okumak isterken scanf() kalvyeden gelen veriyi bir char a yazmaya çalısacaktır(data[0]). scanf in stringi okuması için bir char dizisinin pointerini vermek gerekir. Bu da pointerin pointeri olur.

char *data;
scanf("%s", &data);

Ama scanf, sadece EOF, boşuk ve yeni satıra gelinceye kadar klavyeden okuma yapacaktır. gets() klavyeden bir string almak için her zaman iyi bir yoldur.

char *data; 
scanf("%d", &data);

şeklinde yapınca, şöyle bir uyarı alıyorum:

test.c: In function ‘input’:
test.c:28:10: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘char **’ [-Wformat=]
  scanf("%d", &data);

Yine de çalıştırılabilir dosyayı oluşturuyor fakat rakam girip, enter’a bastıktan sonra aşağıdaki gibi bir hata alıyorum.

Max: 30
Parçalama arızası (çekirdek döküldü)

Galiba benim hatam :slight_smile:
scanf("%d", …) yerine scanf("%s", …) yazmak gerek

Bu sefer de şöyle bir uyarı verdi:

test.c: In function ‘input’:
test.c:28:10: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat=]
  scanf("%s", &data);

Ve yine enter’a bastıktan sonra aynı hatayı aldım.

Yani benim burada asıl öğrenmek istediğim, prompt da bir pointer fakat biz bu pointer’a string atamadığımız halde, printf("%s", prompt); yazarak prompt argümanını ekrana yazdırabiliyoruz. Aynı durum data için neden geçerli değil?

Bu kodda çalışıyor ya anlamadım.

Asıl sorununu bilmiyorum cidden. Ama scanf in yetersiz olduğu cok konu var. İnternette aradım ama anlamlı bir cevap bulamadım :confused:

1 Beğeni

Evet, ben de aşağıdaki gibi yapınca sorun oluşmuyor.

int input(char *prompt){
	/*
	Python'dakine benzer bir input();
	fonksiyonu.
	*/
	char data[10];
	printf("%s", prompt);
        scanf("%s", data);
        /*veya scanf yerine gets'i de kullanabiliyorum.
	gets(data);*/
	return atoi(data);
}

Ama işte data'yı tıpkı prompt gibi bir pointer olarak kullanamadım.

Her seyden once:

String uretip maksimum uzunluk almayan hic bir fonksiyonu asla kullanma.

Normal yayin akisimiza donuyoruz:


Hayir. Buradaki sorun ilk data’nin 10’luk bir char array’ine isaret etmesi, ikinci datanin ise hic bir yere isaret etmemesi. Initialize edilmemis deger kullaniyorsun.


Evet ama kullanmamalisin. Manual sayfasindan:

DESCRIPTION
       Never use this function.

Hayir, tek pointer (char*) vermek gerekir . scanf(2):

 s      Matches a  sequence  of  non-white-space  characters;  the  next
        pointer  must be a pointer to the initial element of a character
        array that is long enough to hold the  input  sequence  and  the
        terminating null byte ('\0'), which is added automatically.  The
        input string stops at white space or at the maximum field width,
        whichever occurs first.

gcc:

a.c:7:13: warning: format ‘%s’ expects argument of type ‘char *’, but
argument 2 has type ‘char **’ [-Wformat=]
     scanf("%s", &data);
            ~^   ~~~~~

(alintilari ekrana sigsin diye formatladim)


Bu arada [] operatorunu makro olarak dusunebilirsin:

x[y] ==> *(x + y)

&data[0]'in data ile ayni olmasinin sebebi bu. &0[data] ile ayni olmasinin sebebi de bu.

1 Beğeni

@aib

Cevap için teşekkür ederim.

Peki, aşağıdaki prompt bir yere işaret ediyor mu?

int input(char *prompt){
	printf("%s", prompt);

Yani henüz anlayamadığım şey şu:

char *prompt pointer’ını printf("%s", prompt) yazıp, input("Max: "); şeklinde kullanabiliyoruz.

ancak char *data için scanf("%s", data); yazıp, data’yı return edemiyorum.

Bu ikisi arasında ne fark var acaba?

scanf("%s", data);

gözden kaçmış herhalde & koymayı unutmayalım bitwise operatör oldugundan dolayı yakalayamaz.
Compiler hata vermiyecektir.

& koyduğum zamanda da Çekirdek döküldü hatası alıyorum.

Şu şekilde çalışıyor, sıkıntı yok bunda.

int input(char *prompt){
	char data[10];
	printf("%s", prompt);
        scanf("%s", data);
	return atoi(data);
}

Benim sorum şununla alakalı:

Ben de bu şekil de çalışmıyor bu ara da nedense

The C library function  **int atoi(const char *str)**  converts the string argument  **str**  to an integer (type int).

return edemiyorum o şekilde data içerisini.

Bu arada atoi fonksiyonunun aldığı argumente bakarsak şurayı okumakta yarar var.

`char*`  is a  **mutable**  pointer to a  **mutable**  character/string.

`const char*`  is a  **mutable**  pointer to an  **immutable**  character/string.

Bende bir sıkıntı vermedi. return ediyor.

Cagiran bilir. Runtime’dan (calisma ani; kod yazilma veya compile edilme ani degil) bahsediyoruz.

E cunku parametre olarak "Max: " pasliyosun. 6’lik char array’i.

char *foo; input(foo); dene.

Bunun da paraleli scanf("%s", "Max: ") cagirmak olacaktir. Bunu yapabiliyorsun.

data char* oldugu icin int fonksiyondan return edememen normal.

bu arada tamam scanf için şurayı okudum :slight_smile:

 By default the variable itself points to the base address and therefore to access base address of string, there is no need of adding an extra ‘&’

char veri tipi için geçerli :smiley:

Tamam, galiba anlamaya başlıyorum. prompt pointer’ına başka bir fonksiyonda bir değer ataması yapılıyor. Ama data pointer’ına bir değer ataması RunTime esnasında yapılmaya çalışılıyor, o yüzden hata veriyor diye anlıyorum. Yanlış anlıyorsam lütfen düzeltin.