C'de string içerisinde sayı ve karakter çekmek?

Başlatan Mucit23, 22 Ekim 2014, 13:22:45

Mucit23

Birşey sorayım,

Sorumu Hesap makinesi örneği üzerinden giderek anlatsam sanırım daha iyi olur

Hesap makinesinde iki değerin toplamı için örneğin 123+456 gibi bir değer giriyoruz. Burada girilen string içerisinden 123 değerini bir tam sayı değişkenine, ortada girilen '+' karakterini bir char türünde değişkene ve en sondaki 456 değerini ayrı bir tam sayı değişkenine aktarmak istiyorum. Bu işlemi C'nin kendi string fonksiyonlarıyla nasıl yaparım?

MrDarK

Hocam merhaba ;

Önce string içerisindeki yerleri parçalamak gerekiyor.

Bu link string parçalamasını anlatıyor ;

http://www.cplusplus.com/reference/cstring/strtok/

Bu fonksiyonda ascii olarak yazılmış sayıyı int türüne dönüştürmekten bahsediyor ;

http://www.cplusplus.com/reference/cstdlib/atoi/

Ama ben genelde kendi fonksiyonlarımı kendim yazıyorum.
Picproje Eğitim Gönüllüleri ~ MrDarK

Mucit23

Teşekkürler,
Sanırım strtok fonksiyonu benim işimi görüyor. Nasıl kullanacağımı anladım ama iki sayı arasındaki karakteri nasıl seçeceğimi çözemedim.

char dizi[]="123+456";
char *sayi1;
char *sayi2;
char ortakarakter;
olsa

sayi1=strtok(dizi,"+-/*");
Dersek "123" dizisini sayi1 isimli char diziye gönderir.

Bundan sonra ortadaki karakteri ve ortadaki karakterden sonraki diziyi nasıl alırım?

Klein

Sayı adedi ve format her zaman sabitse; en kolay scanf(..) fonksiyonları ile yapabilirsiniz.

int a, b;
char c;
sscanf(text, "%d%c%d", &a, &c, &b);


not: bir süredir scanf kullanmıyorum. söz diziminde ufak tefek hatalar olabilir.

RaMu

Kullandığın derleyici hbüyük ihtimalle char değişkeni unsigned int olarak tanımlamıştır,
yani char veya int değişkene almanın ne farkı olacak.
printf gibi bir fonksiyonda int tanımlı değişkeninin char karşılığını göster dediğinde problem olmuyorsa tamamdır.
yani;
unsigned int a;
char c;
printf("a'nın degeri=%u,  c'nin degeri=%u ", a,  c);

Buna hata vermiyorsa char a veya unsigned int değişkene almanın farkı olmaz.

Birde dizide elemanlar nasıl saklanıyor önemli,
dizi[]={"123"};
bunu alıp değişkenlere atsan, 0x31,0x32,0x33 görebilirsin.

Bende hazır fonksiyonları pek kullanmadığım için o konuda pek birşey söylemek istemiyorum.
Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html

mufitsozen

#5
Alıntı yapılan: Mucit23 - 22 Ekim 2014, 14:19:07
Teşekkürler,
Sanırım strtok fonksiyonu benim işimi görüyor. Nasıl kullanacağımı anladım ama iki sayı arasındaki karakteri nasıl seçeceğimi çözemedim.

char dizi[]="123+456";
char *sayi1;
char *sayi2;
char ortakarakter;
olsa

sayi1=strtok(dizi,"+-/*");
Dersek "123" dizisini sayi1 isimli char diziye gönderir.

Bundan sonra ortadaki karakteri ve ortadaki karakterden sonraki diziyi nasıl alırım?

int num1,num2;   /* diye tanimlarsak */

sayi1 = strtok(dizi,"+");
sayi2 = strtok(NULL,"+");  /* NULL parameter yuzunden strtok multithreaded değildir. dikkat! */

ortakarakter = *(dizi+strlen(sayi1));

int1 = atoi(sayi1);
int2 = atoi(sayi2);

Aptalca bir soru yoktur ve hiç kimse soru sormayı bırakana kadar aptal olmaz.

X-Fi

Alıntı yapılan: Mucit23 - 22 Ekim 2014, 14:19:07
Teşekkürler,
Sanırım strtok fonksiyonu benim işimi görüyor. Nasıl kullanacağımı anladım ama iki sayı arasındaki karakteri nasıl seçeceğimi çözemedim.

char dizi[]="123+456";
char *sayi1;
char *sayi2;
char ortakarakter;
olsa

sayi1=strtok(dizi,"+-/*");
Dersek "123" dizisini sayi1 isimli char diziye gönderir.

Bundan sonra ortadaki karakteri ve ortadaki karakterden sonraki diziyi nasıl alırım?

strtok ile geri dönüş veri olarak değil pointer adresi olarak alınır. Herhangi bir kopyalama olmaz. Adres üzerinden diziyi izleyip istediğiniz veriyi parse edebilirsiniz.
http://www.coskunergan.dev/    (Yürümekle varılmaz, lakin varanlar yürüyenlerdir.)

mir_as82

int main()
{
   char islem[10];

   int op1, op2;
   char yapilacakIslem;
   int k;
   printf("islemi girin : ");
   scanf("%s", islem);
   for (k = 0; k < sizeof(islem); k++) {

      if (!isdigit(islem[k])) {
         yapilacakIslem = islem[k];
         break;
      }
   }
   op1 = atoi(islem);
   op2 = atoi(islem + k * 1 + 1);
   printf("%d\n", op1 );
   printf("%d\n", op2 ) ;
   printf("%c\n", islem[k]);
   return 0;
}

mufitsozen

#8
-----------
Aptalca bir soru yoktur ve hiç kimse soru sormayı bırakana kadar aptal olmaz.

mir_as82

#9
Hocam bu strtok fonksiyonunda. ilk parametre ayırım yapılacak string, ikinci parametre ise ayırım yapıcı karakterler.
Burada şunu merak ediyorum. Geri dönüş değeri olarak o bulduğu karakterlerin adresini mi geri döndürüyor?
ikinci sorum ise, bir örnekte gördüm internette ilk parametre NULL pointer olarak veriliyor. Bunun nedeni nedir?
Örnek şu:
/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

Burada strtok geri dönüş değeri bulduğu adresten bir sonraki adres değer olmaz mı?
Hocam anladım olayı : ). Bu benim dizimi değiştiren bir fonksiyon aslında. Aklıma bu hiç gelmemişti.
Tabi NULL parametre vererek benim dizimin içine yerleştirdiği NULL karakteri o fonksiyona tekrar gönderiyorum ki, artık başlangıç noktan burası diyorum.

X-Fi

#10
Alıntı yapılan: mir_as82 - 22 Ekim 2014, 16:32:25
Hocam bu strtok fonksiyonunda. ilk parametre ayırım yapılacak string, ikinci parametre ise ayırım yapıcı karakterler.
Burada şunu merak ediyorum. Geri dönüş değeri olarak o bulduğu karakterlerin adresini mi geri döndürüyor?
ikinci sorum ise, bir örnekte gördüm internette ilk parametre NULL pointer olarak veriliyor. Bunun nedeni nedir?
Örnek şu:
/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

Burada strtok geri dönüş değeri bulduğu adresten bir sonraki adres değer olmaz mı?
Hocam anladım olayı : ). Bu benim dizimi değiştiren bir fonksiyon aslında. Aklıma bu hiç gelmemişti.
Tabi NULL parametre vererek benim dizimin içine yerleştirdiği NULL karakteri o fonksiyona tekrar gönderiyorum ki, artık başlangıç noktan burası diyorum.

Hocam diziler NULL ile biter. Bu örnek strtok çalışmasını biraz karışık anlatmış. Şöyle işliyor dizi içeriğini tarayıp Boşluk,virgül,Nokta,Tire herhangi birini bulduğu yere NULL yazarak değiştiriyor dizinin birsonraki pointer adresini geri dönüyor. Sonra bu adresi ekrana çıktı göndererek kullanıyor. Devamında da kalan diziyi (NULL karakterine kadar) özel karaklerler ile parçalamaya devam ediyor.

Aynı şey strchr,strpbrk ile de kolayca yapılır amac uzun dizilerde tek fonksiyon ile diziyi parçalamak. Daha az kod kollanmak.
http://www.coskunergan.dev/    (Yürümekle varılmaz, lakin varanlar yürüyenlerdir.)

mir_as82

#11
Peki hocam ilk parametreye NULL geçiyor bu neden? Yani onun ozel bir manasi mi var??
Aklima şu geldi. Acaba statik olarak bir pointer degisken  tutup, Fonksiyona ilk parametre olarak NULL gecilirse bir önceki adresten baslayarak NULL u buluyor ve o NuLL dan bir sonra sini adres olarak parametre mi aliyor acaba.

Mucit23

Cevaplar için teşekkürler

Alıntı yapılan: X-Fi - 22 Ekim 2014, 17:31:46
Hocam diziler NULL ile biter. Bu örnek strtok çalışmasını biraz karışık anlatmış. Şöyle işliyor dizi içeriğini tarayıp Boşluk,virgül,Nokta,Tire herhangi birini bulduğu yere NULL yazarak değiştiriyor dizinin birsonraki pointer adresini geri dönüyor. Sonra bu adresi ekrana çıktı göndererek kullanıyor. Devamında da kalan diziyi (NULL karakterine kadar) özel karaklerler ile parçalamaya devam ediyor.

Aynı şey strchr,strpbrk ile de kolayca yapılır amac uzun dizilerde tek fonksiyon ile diziyi parçalamak. Daha az kod kollanmak.

Hocam şimdi strtok fonksiyonunu daha iyi anladım. Ama sanırım işimi görmüyor.

Şöyle;
Alıntı yapılan: mufitsozen - 22 Ekim 2014, 14:54:44
int num1,num2;   /* diye tanimlarsak */

sayi1 = strtok(dizi,"+");
sayi2 = strtok(NULL,"+");  /* NULL parameter yuzunden strtok multithreaded değildir. dikkat! */

ortakarakter = *(dizi+strlen(sayi1));

int1 = atoi(sayi1);
int2 = atoi(sayi2);

Abi verdiğin kod parçasını denedim ve aşağıdaki gibi bir kod yazdım

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>

char data[]="123+456";
char *value1;
char *value2;
char islem;

int main()
{ 
 
  while(1)
  {
    value1=strtok(data,"+");
    value2=strtok(NULL,"+");
    islem=data[3];
    printf("1. Deger=%s\n\r",value1);   
    printf("2. Deger=%s\n\r",value2);
    printf("islem=%c\n\r",islem);
    getch();    
  }
}


Burada strtok fonksiyonu çalışıyor. value1=strtok(data,"+"); komutunda strtok + gördüğü yere null koyup önceki karakterleri value1 dizisine gönderiyor.
value2=strtok(NULL,"+"); Bu kodda çalışıyor value2 dizisinin değeri "456" oluyor ama çalışmasını anlayamadım. @Müfit hocam neden null gönderdik?

Dediğim gibi yukarıdaki kodlar çalışıyor ama benim orta karakterimi strtok fonksiyonu siliyor yerine null yazıyor.
yukarıdaki işlemlerden sonra dizinin 3. elemanına bakıyorum islem=data[3];

işlem değeri null çıkıyor normal olarak. Bu sorunu nasıl çözerim?

MrDarK

Alıntı YapDediğim gibi yukarıdaki kodlar çalışıyor ama benim orta karakterimi strtok fonksiyonu siliyor yerine null yazıyor.
yukarıdaki işlemlerden sonra dizinin 3. elemanına bakıyorum islem=data[3];

işlem değeri null çıkıyor normal olarak. Bu sorunu nasıl çözerim?

Hiçbir işlem yapmadan önce yani strtok işlemine tabi tutmadan önce işlemin ne olduğunu öğrenin. Onun içinde strchr fonksiyonu yardımımıza koşuyor.
Örnek : http://www.cplusplus.com/reference/cstring/strchr/

strstr fonksiyonu ile de uzun cümle karşılaştırması yapabilirsin.
Link : http://www.cplusplus.com/reference/cstring/strstr/
Picproje Eğitim Gönüllüleri ~ MrDarK

mir_as82

Hocam bence senin işini bu fonksiyon görmez. Neden dersen. Örnek vereyim
Girilen string "12+20" olsun.= '1', '2', '+' , '2', '0','\0'
ilk çağırmada sana 1 in adresini geri döndürür ve + nın olduğu yere '\0' koyar. Bu strtok fonksiyonu sizin orjinal dizinizde (char dizi) işlem yapan bir fonksiyon. Ve direkt değişikliği onun üstünde yapıyor
ilk çağırmada senin dizi : '1','2','\0' oldu bile. Yani + karakterinin olduğu yere '\0' kondu.
İkinci çağırmanda ise:(Tahminen bu fonksiyonun içinde statik bir değişkende son null karakterin adresi tutuluyor). NULL ile parametre geçince bu statik olarak tutulan adres değişkeninden bir sonrasını alıyor ve diziyi dolaşıp bir sonraki delimiter değişkene kadar ilerliyor ve onu da görünce onun yerine de '\0' koyuyor. sen bu sayede + dan sonraki karakterin adresini alıyorsun.

En son ise NULL paramtere gönderip diziyi dolaşıp orjinal dizinin sonlandıran NULL karakterini görünce '1', '2', '+' , '2', '0','\0' yani bunun sonundaki '\0' ı. işlemini bitiriyor.