C, String Veriler – Char Veri Türü

C dilinde char tipi tamsayı tipidir çünkü C’nin altında karakterler yerine tamsayılar depolanır.

C’de char değerleri 1 byte bellekte saklanır ve değer aralığı -128 ile 127 veya 0 ile 255 arasındadır. Karakterleri temsil etmek için, bilgisayarın sayısal bir kod kullanarak her bir tam sayıyı karşılık gelen bir karakterle eşlemesi gerekir. En yaygın sayısal kod, American Standard Code for Information Interchange anlamına gelen ASCII’dir.

char char_variable = 'A';
#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    char character = 'Z';
    printf("character = %c\n",character);
    printf("character = %d,Stored as integer\n", character);
    return 0;
}

Ekrann görüntüsü

character = Z
character = 90, hence an integer

Bazı fonksiyonlar

int islower(ch)

int isupper(ch)

isalpha(ch)

int isdigit(ch);

int ispunct(ch); //noktalama işareti mi

int isspace(ch)

Char String Dizisi

C programlama dilinde, bir string,  \0 ile sonlandırılmış bir karakter dizisidir.

char c[] = "merhaba dunya";

Derleyici, çift tırnak işaretleri içine alınmış bir dizi karakterle karşılaştığında, varsayılan olarak sonuna bir null karakteri \0 ekler.

merhabadunya\0

Stringleri şu şekilde bildirebilirsiniz:

char s[5];
s[0]s[1]s[2]s[3]s[4]
char c[] = "abcd";
 
char c[50] = "abcd";
 
char c[] = {'a', 'b', 'c', 'd', '\0'};
 
char c[5] = {'a', 'b', 'c', 'd', '\0'};
c[0]c[1]c[2]c[3]c[4]
abcd\0

Başka bir örneğe bakalım:

123char c[5] = “abcde”;

Burada 5 karakterlik bir karakter dizisine 6 karakter (son karakter ‘\ 0’) atamaya çalışıyoruz. Bu kötü ve bunu asla yapmamalısın.

char name[7];
char name[7] = { 'F', 'l', 'a', 'v', 'i', 'o' };
char name[7] = "Flavio";
printf("%s", name);

Fark ettiniz mi “Flavio” 6 karakter uzunluğunda ama ben 7 uzunluğunda bir dizi tanımladım? Neden? Niye? Bunun nedeni, bir dizedeki son karakterin \0 değeri olması, dize sonlandırıcı olması ve onun için boşluk açmamız gerektiğidir.

#include <string.h>

strcpy() // bir char dizisini diğerine kopyalar
strcat() //Bir char dizisini diğerine ekler
strcmp() //iki dizinin eşitliğini karşılaştırır
strncmp() //iki dizinin ilk n karakterini karşılaştırmak için
strlen() // bir char dizisinin uzunluğunu verir.

Geriye String Döndüren Fonksiyonlar

xxxxx myName() {
  return "dijigo";
}

C’deki dizeler, char öğelerinin dizileridir, bu nedenle gerçekten bir dize döndüremeyiz – dizenin ilk öğesine bir işaretçi döndürmeliyiz.

Bu yüzden const char* kullanmamız gerekiyor.

const char* myName() {
  return "dijigo";
}
#include <stdio.h>

const char* myName() {
  return "dijigo";
}

int main(void) {
  printf("%s", myName());
}
const char* name = myName();

Tüm formlar tamamen geçerlidir. Const kullanımına dikkat edin, çünkü işlevden bir sabit değer olan, çift tırnak içinde tanımlanmış bir dize olan bir sabit değer döndürüyorum. C’de bir dize hazır bilgisini değiştiremeyeceğinizi unutmayın. Akılda tutulması gereken başka bir şey de, bir C işlevinden yerel değişken olarak tanımlanan bir dize döndüremeyeceğinizdir, çünkü değişken, işlev yürütmeyi bitirdiğinde otomatik olarak yok edilecek (serbest bırakılacaktır) ve bu nedenle mevcut olmayacaktır. örneğin 

#include <stdio.h>

const char* myName() {
  char name[6] = "dijigo";
  return name;
}

int main(void) {
  printf("%s", myName());
}
hello.c:5:10: warning: address of stack memory
      associated with local variable 'name'
      returned [-Wreturn-stack-address]
  return name;
         ^~~~
1 warning generated.
B��Z> K���⏎

Böyle bir uyarı alırsınız

Doğrusu

const char* myName() {
  char *name = "dijigo";
  return name;
}

İşaretçiler (Pointers) – C

C dilinde, işaretçiler (pointers) bellekte bulunan verilerin adreslerini saklar. İşaretçi değişkenleri, verilerin bellekteki adreslerini saklar ve bu adreslerle çalışır. İşaretçiler, verileri bellekte direk olarak erişmenizi sağlar ve bu sayede verileri daha hızlı işleyebilirsiniz. Ayrıca, fonksiyonlar arasında veri paylaşımı yaparken de işaretçiler kullanılabilir. Özellikle dinamik bellek yönetiminde işaretçiler önemli bir rol oynamaktadır.

Örneğin, bir tam sayı değişkeni oluşturalım ve bu değişkenin adresini işaretçi değişkenimize atayalım:

int x = 5;
int *ptr = &x;

Burada, x değişkeni bir tam sayı olarak tanımlanmıştır ve değeri 5’dir. İşaretçi değişkeni olan ptr, x değişkeninin bellekteki adresini saklar. & operatörü kullanılarak x değişkeninin adresi ptr değişkenine atanmıştır.

Artık, ptr işaretçisi aracılığıyla x değişkenine erişebiliriz:

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

int main()
{
//işaretçi tanımlama
int x = 5;
int *ptr = &x;

//p değişkeninin değerini yazdırma
printf("p değişkeninin değeri: %d", *ptr);
//p değişkeninin adresini yazdırma
printf("p değişkeninin adresi: %p", ptr);
return 0;
}

Pointer tanımlarken * operatörü kullanılır. Bu operatör, değişkenin bir işaretçi olduğunu belirtir. Örneğin, int *ptr ifadesi ptr isimli bir işaretçi tanımlar ve bu işaretçi int tipinde verileri gösterebilir.

Aynı şekilde, işaretçi değişkeninin işaret ettiği bellek adresindeki değerleri almak için de * operatörü kullanılır. Bu operatör, işaretçi tarafından gösterilen bellek adresindeki değeri verir. Örneğin *ptr ifadesi ptr işaretçisi tarafından gösterilen bellek adresindeki değeri verir. Bu nedenle, pointer tanımlarken ve değerini alırken aynı operatör olan * kullanılır.

Şimdi de x değişkeninin değerini işaretçi aracılığıyla değiştirelim.

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

int main()
{
//işaretçi tanımlama
int x = 5;
int *ptr = &x;

*ptr = 10; // x'in değerini 10 yap
printf("x = %d", x); // x = 10
return 0;
}

İşaretçi ptr değişkeni, x değişkeninin bellekteki adresini gösterir. *ptr = 10 ifadesi ile ptr işaretçisi tarafından gösterilen bellek adresindeki değer olan x değişkeninin değeri 10 olarak değiştirilir. Bu nedenle, sonunda printf("x = %d\n", x); ifadesi çalıştığında x’in değeri 10 olacaktır.

Peki iki işaretçiyi birbirine eşitlersek ne olur? Şimdi de buna bakalım

int x = 5; // x değişkeni tanımlanıyor ve 5 değeri atanıyor
int y = 10; // y değişkeni tanımlanıyor ve 10 değeri atanıyor
int *ptr1 = &x; // ptr1 işaretçisi x değişkeninin bellek adresini gösterir
int *ptr2 = &y; // ptr2 işaretçisi y değişkeninin bellek adresini gösterir
ptr1 = ptr2; // ptr1 işaretçisi ptr2 işaretçisi tarafından gösterilen bellek adresi olan y değişkeninin adresini gösterir

Burada, ptr1 işaretçisi x değişkeninin bellekteki adresini, ptr2 işaretçisi ise y değişkeninin bellekteki adresini gösterir. ptr1 = ptr2 ifadesi ile ptr1 işaretçisi ptr2 işaretçisi tarafından gösterilen bellek adresi olan y değişkeninin adresini gösterir. Yani ptr1 artık y değişkeninin adresini gösterir. Bu işlem sonunda, ptr1 ve ptr2 işaretçileri aynı bellek adresini gösterir ve yapılan her işlemde iki işaretçi aynı veriyi etkileyecektir.

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

int main()
{
int x = 5; 
int y = 10; 
int *ptr1 = &x;  // ptr1'in adresini x'in adresine eşitle
int *ptr2 = &y;  // ptr2'nin adresini y'nin adresine eşitle
ptr1 = ptr2; // ptr1'in adresini ptr2'nin adresine eşitle 
*ptr1 = 20; // y değişkeninin değerini 20 yap
printf("y = %d\n", y); // y = 20

return 0;
}

İşaretçileri Fonksiyona Değer Olarak Atama

void setValue(int *ptr, int newValue){
    *ptr = newValue; // işaretçi üzerinden bellekteki değişkenin değeri değiştiriliyor
}

int main(){
    int x = 5;
    int *ptr = &x;
    setValue(ptr, 10); 
    printf("x = %d\n", x); // x = 10
    return 0;
}

Bu örnekte, setValue fonksiyonu işaretçi ve yeni bir değer alır ve işaretçi üzerinden bellekteki değişkenin değerini yeni değere eşitler. main fonksiyonunda, x değişkeni tanımlanır ve ptr işaretçisi x değişkeninin bellek adresini gösterir. Ardından, setValue fonksiyonu ptr işaretçisi ve yeni değer olarak 10’u kullanarak çağrılır. Bu çağrı sonucunda, x değişkeninin değeri 10 olur ve ekrana “x = 10” yazdırılır.

void swapPointers(int *ptr1, int *ptr2){
    int temp = *ptr1;
    *ptr1 = *ptr2;
    *ptr2 = temp;
}

int main(){
    int x = 5;
    int y = 10;
    int *ptr1 = &x;
    int *ptr2 = &y;
    swapPointers(ptr1, ptr2);
    printf("x = %d, y = %d\n", x, y); // x = 10, y = 5
    return 0;
}

Bu örnekte, swapPointers fonksiyonu iki işaretçi alır ve bu işaretçileri kullanarak işaret ettikleri değişkenlerin değerlerini karşılıklı olarak değiştirir. main fonksiyonunda, x ve y değişkenleri tanımlanır ve ptr1 ve ptr2 işaretçileri bu değişkenlerin bellek adreslerini gösterir. Ardından, swapPointers fonksiyonu ptr1 ve ptr2 işaretçileri kullanarak çağrılır ve işaret ettikleri değişkenlerin değerleri karşılıklı olarak değiştirilir. Bu çağrı sonucunda, x değişkeni 10 olur ve y değişkeni 5 olur ve ekrana “x = 10, y = 5” yazdırılır.

Bu fonksiyonu şu şekilde kullanırsak değişkenlerin değeri değişmez. Sadece adresler değişir

void swapPointers(int *ptr1, int *ptr2){
    int *temp = ptr1;
    ptr1 = ptr2;
    ptr2 = temp;
}

int main(){
    int x = 5;
    int y = 10;
    int *ptr1 = &x;
    int *ptr2 = &y;
    swapPointers(ptr1, ptr2);
    printf("x = %d, y = %d\n", x, y); // x = 5, y = 10
    return 0;
}

Char Değişkeni ve Dizilerinin Kullanımı

int main(){
    char c = 'A';
    char *ptr = &c;
    *ptr = 'B';
    printf("c = %c\n", c); // c = B
    return 0;
}

Bu örnekte, c değişkeni ‘A’ karakteri ile başlatılır ve ptr işaretçisi c değişkeninin bellek adresini gösterir. Ardından, ptr işaretçisi kullanarak c değişkeninin değeri ‘B’ karakterine değiştirilir. Bu değişiklik sonucunda, c değişkeni ‘B’ karakteri olur ve ekrana “c = B” yazdırılır.

#include <stdio.h>

int main() {
    char str[] = "Hello, world!";
    char *ptr = str;

    printf("String: %s\n", str);
    printf("Pointer: %s\n", ptr);

    *ptr = 'J';
    printf("String: %s\n", str);
    printf("Pointer: %s\n", ptr);

    return 0;
}

Bu örnekte, str dizisi “Hello, world!” ifadesini içerir ve ptr işaretçisi bu dizinin ilk karakterine işaret eder. Öncelikle, str ve ptr işaretçisi tarafından gösterilen dizi ekrana yazdırılır. Daha sonra, ptr işaretçisi tarafından işaret edilen ilk karakter “J” olarak değiştirilir ve yeniden str ve ptr işaretçisi tarafından gösterilen dizi ekrana yazdırılır. Bu örnekte, ptr işaretçisi tarafından işaret edilen dizi değiştirildiğinde, str dizisi de aynı şekilde değişir.

Bir başka versiyon

#include <stdio.h>

int main() {
    char *str = "Hello, world!";

    printf("String: %s\n", str);

    //str[0] = 'J'; // this will cause a segmentation fault 
    printf("String: %s\n", str);

    return 0;
}

Bu örnekte, str işaretçisi “Hello, world!” ifadesinin ilk karakterine işaret eder ve ekrana yazdırılır. Ancak, str[0] = 'J' satırını yazınca programın hata vermesi ve segmentation fault hatası vermesi gerekir çünkü read-only bellek bölgesinde yer alır ve bu nedenle işaretçi tarafından gösterilen karakter dizisi değiştirilemez.

Başka bir örnek

#include <stdio.h>

int main() {
    int array[] = {10, 20, 30, 40, 50}; // int tipinde bir dizi tanımladık
    int *ptr = array;                   // ptr işaretçisi dizinin ilk elemanına işaret ediyor

    printf("%d\n", *ptr);               // ptr işaretçisi tarafından gösterilen ilk elemanı yazdırıyoruz (10)
    ptr++;                              // ptr işaretçisi bir sonraki elemana işaret ediyor
    printf("%d\n", *ptr);               // ptr işaretçisi tarafından gösterilen ikinci elemanı yazdırıyoruz (20)
    ptr += 2;                           // ptr işaretçisi 2 eleman ilerliyor ve üçüncü elemana işaret ediyor
    printf("%d\n", *ptr);               // ptr işaretçisi tarafından gösterilen üçüncü elemanı yazdırıyoruz (30)
    return 0;
}

Bu örnekte, ptr++ ve ptr += 2 gibi operatörler ile işaretçi 2 veya daha fazla eleman ilerletilebilir. Bu işlemlerle işaretçi tarafından gösterilen eleman değişebilir ve dizinin diğer elemanlarına erişmek mümkün olabilir.

Şimdi de char dizisi şeklinde kullanımına bakalım

#include <stdio.h>

int main() {
    char *ptr = "dijigo";   // ptr işaretçisi "dijigo" ifadesinin ilk karakterine işaret ediyor

    printf("%c\n", *ptr);   // ptr işaretçisi tarafından gösterilen ilk karakteri yazdırıyoruz (d)
    ptr++;                  // ptr işaretçisi bir sonraki karaktere işaret ediyor
    printf("%c\n", *ptr);   // ptr işaretçisi tarafından gösterilen ikinci karakteri yazdırıyoruz (i)
    ptr += 2;               // ptr işaretçisi 2 karakter ilerliyor ve dördüncü karaktere işaret ediyor
    printf("%c\n", *ptr);   // ptr işaretçisi tarafından gösterilen dördüncü karakteri yazdırıyoruz (j)
    return 0;
}

Bu örnekte, ptr++ ve ptr += 2 gibi operatörler ile işaretçi 1 veya daha fazla karakter ilerletilebilir. Bu işlemlerle işaretçi tarafından gösterilen karakter değişebilir ve “dijigo” ifadesinin diğer karakterlerine erişmek mümkün olabilir. Ancak bu gibi işlemleri yaparken dizi içinde sadece okuma işlemi yapabilirsiniz. Diziyi değiştiremezsiniz.

Eğer dizi karakterlerini değiştirmek istiyorsak

#include <stdio.h>

int main() {
    char str[] = "dijigo";    // char tipinde bir dizi tanımladık
    char *ptr = str;          // ptr işaretçisi dizinin ilk karakterine işaret ediyor

    printf("%c\n", *ptr);     // ptr işaretçisi tarafından gösterilen ilk karakteri yazdırıyoruz (d)
    *ptr = 'D';               // ptr işaretçisi tarafından gösterilen ilk karakteri değiştiriyoruz (D)
    printf("%c\n", *ptr);     // ptr işaretçisi tarafından gösterilen ilk karakteri yazdırıyoruz (D)
    ptr++;                    // ptr işaretçisi bir sonraki karaktere işaret ediyor
    printf("%s\n", str);      // dizinin tüm elemanlarını yazdırıyoruz (Dijigo)
    return 0;
}

while döngüsü ile kullanımı

#include <stdio.h>

int main() {
    char str[] = "dijigo";   // char tipinde bir dizi tanımladık
    char *ptr = str;         // ptr işaretçisi dizinin ilk karakterine işaret ediyor
    while(*ptr != '\0'){      // ptr işaretçisi tarafından gösterilen karakter '\0' olana kadar döngü devam eder
        printf("%c ", *ptr); // ptr işaretçisi tarafından gösterilen karakteri yazdırıyoruz
        ptr++;               // ptr işaretçisi bir sonraki karaktere işaret ediyor
    }
    return 0;
}

Bu örnekte, ptr işaretçisi ile dizinin her karakterine erişiyoruz ve döngü içinde printf ile ekrana yazdırıyoruz. Dizinin sonunda '\0' karakteri vardır ve bu karakter döngünün sonlandırılmasını sağlar. Bu örnekte dizinin içerisinde yer alan her bir karakteri okuyup yazdırıyoruz.

while(*ptr != ‘\0’) ifadesi while(*ptr) ifadesi ile aynı anlamı taşır. ptr işaretçisi tarafından gösterilen karakter ‘\0’ olana kadar döngü devam eder. ‘\0’ karakteri C dilinde boolean değer olarak false değerini temsil eder. Bu yüzden while(*ptr) ifadesi ile if(*ptr != ‘\0’) ifadesi arasında bir fark yoktur.

while(*ptr) {
    printf("%c ", *ptr);
    ptr++;
}

Bu şekilde de while döngüsünü yazabilirsiniz.

char str[] = "dijigo";
char *ptr = str;
while(*++ptr) {
    printf("%c ", *ptr);
}

while(*++ptr) ifadesi ile döngü yazarsanız, işaretçi önce bir sonraki karaktere işaret eder ve sonra karakterin değerini kontrol eder. Bu yüzden ilk satırda ptr işaretçisi bir sonraki karaktere işaret eder ve döngü içerisinde ptr işaretçisi tarafından gösterilen karakteri ekrana yazdırır.

char str[] = "dijigo";
char *ptr = str;
while(*++ptr) {
    printf("%c ", *ptr);
}

Bu örnekte, döngü ilk başladığında işaretçi str dizisinin ilk karakterinden bir sonraki karaktere işaret eder, döngü içerisinde ptr işaretçisi tarafından gösterilen karakteri ekrana yazdırır. Bu şekilde dizinin ilk karakteri atlanır.

Bu kod ekrana “ijigo” yazar. ptr işaretçisi başlangıçta “dijigo” dizinin ilk karakterinden bir sonraki karaktere işaret eder. Döngü içerisinde ptr işaretçisi tarafından gösterilen karakteri ekrana yazdırır. Bu nedenle, dizinin ilk karakteri “d” atlanır ve ekrana “ijigo” yazdırılır.

char str[] = "dijigo";
char *ptr = str;
while(*++ptr) ;
printf("%c ", *ptr);

Bu kod, “dijigo” dizisinde işaretçi ptr ile gezinir ve dizinin sonuna kadar döngüyü sürdürür. Ancak döngü sonunda printf("%c ", *ptr); ile karakteri ekrana yazdırmaz çünkü while döngüsünün sonunda ptr işaretçisi ‘\0’ karakterine işaret ediyor. Bu yüzden ekrana hiçbir şey yazdırılmaz. eğer while döngüsünün sonunda printf(“%c “, *ptr); yazmak istiyorsanız, while döngüsünün sonunda ptr işaretçisini bir geriye gitmemiz gerekir.

char str[] = "dijigo";
char *ptr = str;
while(*++ptr); 
printf("%c ", *--ptr);
#include <stdio.h>

int main() {
 char *str1 = "dijigo"; // 6 değeri kadar bellekte yer kaplar.
 char *str2 = str1; // 6 değeri kadar bellekte yer kaplar.
 //str1 1 artır
    ++str1;
    //ekrana str1 yazdır
    printf("%s", str1); //ijigo
    //str2 yazdır
    printf("%s", str2); //dijigo
    printf("%ld", str2-str1); // -1 değeri döner. çünkü str1 1 arttırıldı ve str2 ile karşılaştırıldı.

}
#include <stdio.h>

int main() {
 char *str1 = "dijigo"; 
 char *str2 = str1; 
    while(*++str1); // while(*str1++); // while(*str1); str1++; // while(*str1 != '\0') str1++;
    printf("%ld\n", str2-str1); // -6 değeri döner.
}

Bu örnekte, str1 işaretçisi “dijigo” dizinin başlangıcını işaret ederken, str2 işaretçisi de str1 işaretçisini kopyaladığı için aynı diziyi işaret etmektedir.

While döngüsünde, str1 işaretçisi dizinin sonunda kalana kadar her bir karakteri gezmektedir. Döngü bittiğinde str1 işaretçisi dizinin sonunda kalır.

printf() fonksiyonunda, str2 işaretçisi dizinin başlangıcını, str1 işaretçisi ise dizinin sonunu işaret etmektedir. Bu nedenle str2-str1 işlemi, dizinin başlangıcı ile sonu arasındaki adres farkını verir ve bu değer negatif olacaktır. Özellikle str1 işaretçisi dizinin sonunda kalıyorsa str2-str1 işlemi -6 döndürür.

#include <stdio.h>

int main() {
 char *str1 = "dijigo"; // 6 değeri kadar bellekte yer kaplar.
 char *str2 = str1; // 6 değeri kadar bellekte yer kaplar.
 //str1 1 artır
    //ekrana str1 yazdır
    while(*++str1); // while(*str1++); // while(*str1); str1++; // while(*str1 != '\0') str1++;
    printf("%s\n", str1); //boşluk
    printf("%s\n", str2); //dijigo
    printf("%ld\n", str2-str1); // -6 değeri döner.

}

Python Random Fonksiyonu İle Oyun Yapma

Aklımdaki sayıyı bil oyunu.

import random
can=3
rastgele=random.randint(0,20)
while(True):
  try:
    if(can==0):
      print("Kaybettin. Benim aklımdaki sayı: ",rastgele)
      break

    tahmin=int(input("Aklımdaki sayıyı bil (0-20 arası):"))
    if(rastgele==tahmin):
      print("Tebrikler doğru cevap")
      break

    can-=1

    if(can!=0):
      if(tahmin>rastgele):
        print("Daha küçük bir sayı gir")
    
      if(tahmin<rastgele):
        print("Daha büyük bir sayı gir")
  

    if(can!=0):
      print(f"{can} hakkın kaldı.")
  except:
    print("Adama ol düzgün sayı gir.")

HTML Site Örneği – 2

<!DOCTYPE html>
<html>

<head>
   <title>Ahmet KADAK' ın Yazılım Evi</title>
</head>

<body style="background-color: gray;">
   <h1 style="color: #de0000;">Ben Malatya' da doğdum. </h1>
   <a href="https://kadakod.com/">Benim Sitem</a>


   <h1>Başlık 1</h1>

   <ul>
      <li>Elma</li>
      <li>Armut</li>
      <li>Kivi</li>
      </li>
   </ul>
   <img width="60px" height="40px"
      src="https://www.taxi-times.com/wp-content/uploads/2020/08/2020-08-11-Togg-kommt-elektrisch-nach-Deutschland-Foto-TOGG.jpg">

   <p style="font-size: 18px;">
      Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's
      standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to
      make
   </p>

   <table border="1">
      <tr>
         <td>Pazartesi</td>
         <td>Salı</td>
         <td>Çarşamba</td>
         <td>Perşembe</td>
      </tr>
      <tr>
         <td>Elma</td>
         <td>Et</td>
         <td>portakal</td>
         <td>çikolatalı süt</td>
      </tr>
    </table>

</body>

</html>