Not: Bu yazıdaki kodlar ve register isimleri (TXDR, CFG1, DSIZE) STM32H7 HAL'ine göredir.

SPI ile çalışırken, IOC dosyasında DataSize parametresine 8-bit, 16-bit veya 32-bit gibi değerler verebiliyorum. Fakat veri gönderirken kullandığımız fonksiyonun signature'ı şöyle:

HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)

Burada pData, uint8_t *pData olarak tanımlanmıştır.

Bunu fark edince şu sorular aklıma geldi: DataSize'ı IOC dosyasında neden ayarlıyorum? DataSize tam olarak ne işe yarıyor? Bu durum veri kaybına yol açar mı?

Diyelim ki yapımız şu:

uint16_t TX_Data[] = {1, 2, 3, 4};
HAL_SPI_Transmit_IT(&hspi1, (uint8_t*)TX_Data, 4);

1. uint8_t* cast'i neden veri kaybettirmez?

uint16_t TX_Data[4], memory'de 8 byte'lık ardışık bir alandır. uint16_t* de uint8_t* de aynı address'i gösterir. Pointer type, compiler'a o address'ten kaç byte okunacağını ve ++ ile kaç byte ilerleneceğini söyler.

Yani (uint8_t*)TX_Data cast'i veriyi deÄŸiÅŸtirmez. Sadece compiler'a "bunu byte byte iÅŸle" deriz.

2. HAL pointer'ı tekrar orijinal type'ına cast ediyor

HAL_SPI_Transmit_IT, verdiğimiz uint8_t* pointer'ını hspi->pTxBuffPtr içinde saklar. Transfer başlamadan önce DataSize'a bakarak hangi ISR'ın çalışacağını seçer. 16-bit için seçilen SPI_TxISR_16BIT, pointer'ı tekrar uint16_t* olarak cast eder.

/* Set the function for IT treatment */
if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
{
  hspi->TxISR = SPI_TxISR_32BIT;
}
else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
{
  hspi->TxISR = SPI_TxISR_16BIT;
}
else
{
  hspi->TxISR = SPI_TxISR_8BIT;
}

SPI_TxISR_16BIT içinde işimize yarayan kısım şu:

static void SPI_TxISR_16BIT(SPI_HandleTypeDef *hspi)
{
  /* Transmit data in 16 Bit mode */
  __IO uint16_t *ptxdr_16bits = (__IO uint16_t *)(&(hspi->Instance->TXDR));

  *ptxdr_16bits = *((uint16_t *)hspi->pTxBuffPtr);   // uint16_t* cast'i, 2 byte okunur
  hspi->pTxBuffPtr += sizeof(uint16_t);              // pointer 2 byte ilerler
  hspi->TxXferCount--;                               // Size kaç verildiyse o kadar azalır

  /* ... TxXferCount == 0 olunca TXP interrupt kapatılır ... */
}

Yani:

  • pTxBuffPtr her seferinde 2 byte (sizeof(uint16_t)) ilerler. Böylece bir sonraki transferde dizideki bir sonraki uint16_t elemanı okunur.
  • TxXferCount (bizim verdiÄŸimiz Size) her ISR çaÄŸrısında 1 azalır. Yani ISR'ın kaç kez çalışacağını, baÅŸka bir deyiÅŸle kaç tane 16-bit frame gönderileceÄŸini belirler. Bu deÄŸer byte sayısı deÄŸildir.

Yani zincir şöyle oluyor:

  1. uint16_t a[], (uint8_t*)a cast'i ile fonksiyona parameter olarak veriliyor.
  2. HAL bunu uint8_t* olarak pTxBuffPtr içinde saklıyor.
  3. HAL_SPI_Transmit_IT içinde DataSize kontrol ediliyor ve ISR seçiliyor.
  4. ISR çalışırken SPI_TxISR_16BIT içinde tekrar uint16_t* cast'i yapılıyor ve o address'ten 2 byte birden okunuyor.

3. Peki DataSize tam olarak ne işe yarıyor?

CubeMX'te seçtiğimiz DataSize, MX_SPI1_Init() içinde şöyle set edilir:

hspi1.Init.DataSize = SPI_DATASIZE_16BIT;

Bu değer, SPI'ın CFG1 register'ındaki DSIZE field'ına yazılır ve üç yerde kullanılır.

3.1. Hardware: Bir frame kaç bit?
Bir frame'de SCK'nın kaç clock pulse üreteceğini belirler. 16-bit seçtiğimizde, CS aktifken 16 clock pulse çıkar ve 16 bit shift edilir.

3.2. Hardware: TXDR access width ve FIFO packing
TXDR'a 8, 16 veya 32-bit access yapılabilir. Access width, FIFO'ya tek seferde kaç bit'lik data girdiğini belirler. Access width frame size'dan küçük olmamalıdır. Büyükse data packing devreye girer: örneğin 16-bit frame'de yapılan 32-bit write, FIFO'ya tek seferde 2 frame koyar. Access width DSIZE ile uyumsuz olursa frame'ler yanlış pack edilir.

3.3. Software: HAL hangi ISR'ı seçecek?
Bölüm 2'deki seçim kodu, DataSize'a bakarak TxISR function pointer'ını set eder. pData'nın uint8_t* olarak gelip ISR içinde uint16_t* olarak cast edilmesinin kararı burada verilir.

4. Peki veri kaybı ne zaman olur?

DataSize, buffer'ın element type'ı ile uyumluysa veri kaybı olmaz. Uyumsuzsa olur. Aynı diziyi DataSize = 8-bit iken gönderdiğimizi düşünelim:

uint16_t TX_Data[] = {1, 2, 3, 4};   // memory'de: 01 00 02 00 03 00 04 00
HAL_SPI_Transmit_IT(&hspi1, (uint8_t*)TX_Data, 4);   // DataSize = 8BIT

Size, byte sayısı değil frame sayısıdır. 8-bit modda 4 frame = 4 byte gider: 01 00 02 00. Yani dizinin sadece ilk iki elemanı gönderilir; 3 ve 4 hiç gitmez.

Kısacası (uint8_t*) cast'i tek başına veri kaybettirmez. Veri kaybına, DataSize'ın buffer type'ı ile uyumsuz olması yol açar.

1) Car Sınıfı

Bir Car sınıfı oluşturun. Bu sınıfın Model, Year ve Color adında üç özelliği (property) olsun. Bu özelliklere sınıf dışından erişilebilmeli ve değer atanabilmeli. Ayrıca DisplayInfo adında bir metot ekleyin; bu metot, aracın modelini, üretim yılını ve rengini ekrana yazdırsın.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        public class Car
        {
            public string Model { get; set; }
            public string Color { get; set; }
            public int Year { get; set; }

            public void DisplayInfo()
            {
                Console.WriteLine("
                
                
                {0}, Color: {1}, Year: {2}", Model, Color, Year);
            }
        }
        static void Main(string[] args)
        {
            Car car = new Car();
            Console.Write("Model: ");
            car.Model = Console.ReadLine();
            Console.Write("Year: ");
            car.Year = Convert.ToInt32(Console.ReadLine());
            Console.Write("Color: ");
            car.Color = Console.ReadLine();
            car.DisplayInfo();

            Console.ReadLine();
        }
    }
}

2) Student Sınıfı

Bir Student sınıfı oluşturun. Bu sınıfın Name, Grade ve StudentID adında üç özelliği (property) olsun.

Grade özelliğine yalnızca 0 ile 100 arasında bir değer atanabilsin. Eğer bu aralığın dışında bir değer atanırsa, program bir uyarı mesajı versin.

DisplayStudentInfo adında bir metot yazın. Bu metot, öğrencinin adını, numarasını ve notunu ekrana yazdırsın.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    internal class Program
    {
        public class Student
        {
            public int Id { get; set; }
            public string Name { get; set; }
            private int grade;
            public int Grade
            {
                get { return grade; }
                set {
                    if (value <= 100 && value > 0)
                    {
                        grade = value;
                    }
                    else
                    {
                        Console.WriteLine("0-100 arasında değil");
                    }
                }
            }
            public void DisplayStudentInfo()
            {
                Console.WriteLine("Öğrenci Bilgileri:");
                Console.WriteLine($"ID: {Id}, İsim: {Name}, Not: {Grade}");
            }
        }
        static void Main(string[] args)
        {
            Student s = new Student();
            s.Name = Console.ReadLine();
            s.Id = Convert.ToInt32(Console.ReadLine());
            s.Grade = Convert.ToInt32(Console.ReadLine());
            s.DisplayStudentInfo();
            Console.ReadLine();
        }
    }
}

3) Rectangle Sınıfı

Bir Rectangle sınıfı oluşturun. Bu sınıfın:

  • Width ve Height adında iki özelliÄŸi (property) olsun.
  • Area adında, yalnızca okunabilir (read-only) bir özelliÄŸi olsun. Bu özellik, dikdörtgenin alanını (geniÅŸlik * yükseklik) döndürsün.
  • Perimeter adında, yine yalnızca okunabilir bir özelliÄŸi olsun. Bu özellik, dikdörtgenin çevresini hesaplayarak döndürsün (2 * (geniÅŸlik + yükseklik)).

Kullanıcıdan bir Rectangle nesnesi oluşturmasını, genişlik ve yükseklik değerlerini girmesini ve ardından alan ve çevre değerlerini ekrana yazdırmasını isteyin.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    internal class Program
    {
        public class Rectangle
        {
            public int width { get; set; }
            public int height { get; set; }
            public double Area
            {
                get {
                    return (double)width * (double)height;
                }
            }
            public int Perimeter { 
                get {
                    return 2*((int)width + (int)height);
                }
            }
        }
        static void Main(string[] args)
        {
            Rectangle rect = new Rectangle();

            Console.Write("GeniÅŸlik deÄŸerini girin: ");
            rect.width = Convert.ToInt32(Console.ReadLine());

            Console.Write("Yükseklik değerini girin: ");
            rect.height = Convert.ToInt32(Console.ReadLine());

            Console.WriteLine($"Dikdörtgenin Alanı: {rect.Area}");
            Console.WriteLine($"Dikdörtgenin Çevresi: {rect.Perimeter}");
            
            Console.ReadLine();
        }
    }
}

Bu yazımızda C# Form uygulamasında OpenGL kullanarak line çizimine bakacağız. Bir OpenGLControl ve bir Button kullanacağız. Butona basıldığında çizme işlemini yapacak.

Buton Olayı

private void button1_Click(object sender, EventArgs e)
{
    // rotationTimer.Start();
    Draw();
}

Draw Metodu

private void Draw()
{
    // OpenGL nesnesi tanımlanır
    OpenGL gl = openGLControl1.OpenGL;

    // Ekran temizlenir
    gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);

    // Matris işlemleri başlatılır
    gl.PushMatrix();
    gl.LoadIdentity();

    // Geometriyi ekrana yerleÅŸtirme
    gl.Translate(0.0f, 0.0f, -6.0f); // Ekrana yerleÅŸtirir
    gl.Rotate(0, 0.0f, 0.0f, 1.0f); // Z ekseni etrafında döndür
    gl.Scale(1.0, 1.0, 1.0); // Ölçeklemede bir değişiklik yapılmadı
    DrawLine(gl);
    // Çizimleri ekrana gönderelim
    gl.Flush();

    // Render iÅŸlemini manuel tetikleyelim
    openGLControl1.DoRender();
}

DrawLine Metodu

private void DrawLine(OpenGL gl)
{
    gl.Begin(OpenGL.GL_LINES);
    gl.Color(1.0f, 0.0f, 0.0f); // Kırmızı
    gl.Vertex(-1.0f, 0.0f, 0.0f); // ilk nokta
    gl.Vertex(1.0f, 0.0f, 0.0f); // ikinci nokta
    gl.End();
}

Bu yazımızda C++ programlama dilinde if else yapılarına değineceğiz. Fakat bu yolculuğa çıkmadan önce algoritma ve koşul ifadelerine değineceğiz.

Algoritma

Algoritma, bir sorunu çözmek veya belirlenmiÅŸ bir hedefe ulaÅŸmak için izlenen yoldur. Amaca ulaÅŸmak için bir baÅŸlangıcı olan ve bir sonu olan iÅŸlemler bütünüdür. Yataktan kalkıp iÅŸe gitmek için genç bir idareci tarafından takip edilen “kalk ve ışılda” algoritmasını düşünün:

  1. Yataktan kalk
  2. Pijamalarını çıkar
  3. DuÅŸ al
  4. Giyin
  5. Kahvaltı yap
  6. İşe git

Bu akış, genç idareciyi kritik kararlar vermeye iyi bir şekilde hazırlar. Aynı adımları farklı sırada yaptığını düşünün:

  1. Yataktan kalk
  2. Pijamalarını çıkar
  3. Giyin
  4. DuÅŸ al
  5. Kahvaltı yap
  6. İşe git

Bu durumda genç idarecimiz işe sırılsıklam gidecektir. Bir bilgisayar programında ifadelerin hangi sırada yürütüleceğini belirlemeye program kontrolü denir.

Sözde Kod

Sözde kod, algoritma geliştirmemize yardımcı olan yapay ve gayri resmi bir dildir. Günlük bir dile benzer: gerçek bir bilgisayar programlama dili olmamasına rağmen uygun ve kullanıcı dostudur.

Bu kodları bilgisayarda çalıştıramayız. Aksine, bir programı C++ gibi bir bilgisayar programlama dilinde yazmaya baÅŸlamadan önce programı “planlamamıza” yardımcı olur. Yukarıda örnek olarak bahsettiÄŸimiz “kalk ve ışılda” algoritması sözde koda örnek olarak verilebilir.

Başka bir örnek:

Bir sayıyı oku
İkinci sayıyı oku
Üçüncü sayıyı oku
İlk iki sayıdan büyük olanı bul
Eğer sonuç değişkeni üçüncü sayıdan büyük ise sonuç değerini yazdır
DeÄŸilse
    ÃœÃ§Ã¼ncü sayıyı yazdır

Koşul İfadeleri

Koşul ifadelerini yazarken farklı değerleri karşılaştırmak için ilişkisel (relational) operatörler, ilişkisel ifadeleri birleştirmek için ise mantıksal (logical) operatörler kullanılır. Operatörler ile ilgili yazımızı buradan inceleyebilirsiniz.

If Seçim İfadesi

Programlama sürecinde, kimi zaman farklı koşullarda programın farklı çalışması gerekmektedir. Örneğin bir bankamatiği ele alalım. Banka kartınızı aldıktan sonra bankamatik size şifre soracaktır. Eğer şifrenizi yanlış girerseniz size uyarı verecektir. Eğer şifrenizi doğru girerseniz sizi hesabınıza yönlendirecektir. Bu tip koşula bağlı karar verme işlemi için kullanabileceğimiz komutlardan ilki if komutudur.

if yapısı akış şeması

if koşulu önce koşul ifadesinin denenmesi ile başlar. Eğer koşul ifadesi true döndürülürse, if koşulundan hemen sonra gelen komut yürütülür. Eğer koşul ifadesi false döndürülürse, bu komut atlanır ve program kaldığı yerden devam eder.

if komut söz dizimi:

if (koÅŸul)
    komut;

Örnek bir kod:

if (yas >= 18)
    cout << "Oy kullanabilirsiniz." << endl;

cout << "İyi günler" << endl;

Bu örnekte eÄŸer yaÅŸ 19 ise (yas >= 18) koÅŸul ifadesi true döndürür ve “Oy kullanabilirsiniz.” yazan komut çalışır. Daha sonra program normal akışına devam eder ve “İyi günler” mesajını yazar. Bu durumda çıktı:

Oy kullanabilirsiniz.
İyi günler

Eğer yaş değeri 17 ise, koşul ifadesi false döndürür. İlk komut yürütülmez ve çıktımız:

İyi günler

If Else Seçim İfadesi

AÅŸağıda if..else yapısının syntax’ı bulunmaktadır:

if (test expression) {
    Body of if
}
else {
    Body of else
}

if...else yapısı, koÅŸulu deÄŸerlendirir ve yalnızca koÅŸul “true” olduÄŸunda if’in gövdesini çalıştırır. KoÅŸulun “false” olması durumunda else gövdesi çalışır.

if...else’in akış ÅŸeması aÅŸağıdaki gibidir:

if...else akış şeması

Örnek:

#include <iostream>
using namespace std;

int main() {
  int age = 17;
  if (age > 18) {
    cout << "The person is an adult ";
  }
  else {
    cout << "The person is not an adult ";
  }
  return 0;
}

Çıktı:

The person is not an adult

Yukarıdaki örnekte age deÄŸiÅŸkeninin deÄŸeri 17. if koÅŸulunun true olabilmesi için age deÄŸiÅŸkeninin deÄŸerinin 18’den büyük olması gerekmektedir. Fakat 18’den küçük olduÄŸu için if koÅŸulu saÄŸlanamaz, bu nedenle kod, else yapısının içinde çalışır ve daha sonra program normal akışına devam eder.

if..else if..else İfadeleri

AÅŸağıda if...else if...else yapısının syntax’ı bulunmaktadır:

if (test expression 1) {
    Body of if
}
else if (test expression 2) {
    Body of else-if
}
else {
    Body of else
}

if... else if... else ifadesinde önce if ifadesinin koÅŸulunu kontrol eder ve if gövdesini yalnızca koÅŸulu True olduÄŸunda çalıştırır. Aksi takdirde, else if deyiminin koÅŸuluna geçer. else if koÅŸulunun True olması durumunda, else if’in gövdesi yürütülür. Birden fazla else if ifadesi olabileceÄŸini unutmayın. Kısaca, tüm koÅŸulların False dönmesi durumunda else gövdesi çalıştırılacaktır.

Aşağıda if..else if..else yapısının akış şeması bulunmaktadır:

if..else if..else akış şeması

Örnek:

#include <iostream>
using namespace std;

int main() {
  int age = 11;
  if (age >= 13 && age < 20) {
    cout << "Person is a teenager ";
  }
  else if (age >= 0 && age < 13) {
    cout << "Person is a prepubescent ";
  }
  else {
    cout << "Person is an adult ";
  }
  return 0;
}

Çıktı:

Person is a prepubescent

Bu örnekte, age deÄŸiÅŸkeninin deÄŸeri 11’dir. İlk if koÅŸulunun saÄŸlanabilmesi için, age deÄŸiÅŸkeninin deÄŸerinin 13’e eÅŸit ya da büyük ve 20’den küçük olması gerekmektedir. Fakat age deÄŸiÅŸkeninin deÄŸeri 11’dir. Bu nedenle bu koÅŸul saÄŸlanamadığı için else if yapısının koÅŸuluna bakılmaktadır. else if yapısının koÅŸulunun saÄŸlanabilmesi için, age deÄŸiÅŸkeninin deÄŸerinin 0’a eÅŸit ya da büyük ve 13’ten küçük olması gerekmektedir. age deÄŸiÅŸkeninin deÄŸeri bu aralıkta olduÄŸundan dolayı bu koÅŸul saÄŸlanır ve “true” olur. Bu sayede else if yapısının içine girer ve konsola “Person is a prepubescent” yazısı yazılır. else yapısının içine girmeyecektir. Çünkü else if yapısının koÅŸulu saÄŸlandığında else yapısına girmez. Fakat else if yapısının koÅŸulu saÄŸlanmasaydı, o zaman else yapısının içine girecekti.

Örnekler

1)

Girilen sayının id değişkeninden büyük olması ya da küçük olması ya da eşit olması koşullarını kontrol eder:

#include <iostream>

using namespace std;

int main(void)
{
  int id;

  cout << "Bir int deÄŸer giriniz: ";
  cin >> id;

  if (id == 21) cout << "Girdiğiniz sayı 21'dir!";
  if (id < 21) cout << "Girdiğiniz sayı 21'den küçüktür!";
  if (id > 21) cout << "Girdiğiniz sayı 21'den büyüktür!";

  return 0;
}

Çıktı:

Bir int deÄŸer giriniz: 20
Girdiğiniz sayı 21'den küçüktür!

2)

#include <iostream>

using namespace std;

int main(void)
{
  int id1, id2;

  id1 = 21;
  id2 = 0;

  if (id1!=0) cout << "id1 değişken değeri 0'dan farklıdır!" << "\n";
  if (id2==0) cout << "id2 deÄŸiÅŸken deÄŸeri 0'a eÅŸittir!" << "\n\n";

  if (id1) cout << "id1 değişken değeri 0'dan farklıdır!" << "\n";
  if (!id2) cout << "id2 deÄŸiÅŸken deÄŸeri 0'a eÅŸittir!";

  return 0;
}

Çıktı:

id1 değişken değeri 0'dan farklıdır!
id2 deÄŸiÅŸken deÄŸeri 0'a eÅŸittir!

id1 değişken değeri 0'dan farklıdır!
id2 deÄŸiÅŸken deÄŸeri 0'a eÅŸittir!

3)

#include <iostream>

using namespace std;

int main(void)
{
  int id;

  cout << "8 * 9 = ? iÅŸleminin sonucunu giriniz: ";
  cin >> id;

  if (id == 72) cout << "Cevabınız doğrudur!";
  else cout << "Cevabınız yanlıştır!";

  return 0;
}

Çıktı:

8 * 9 = ? iÅŸleminin sonucunu giriniz: 70
Cevabınız yanlıştır!

4)

#include <iostream>

using namespace std;

int main(void)
{
  int id;

  cout << "Bir int deÄŸer giriniz: ";
  cin >> id;

  if(id%2) {
    cout << "Girdiğiniz sayı tek bir sayıdır: " << id << "\n";
    cout << "Sayının 3 katı: " << 3 * id;
  }
  else {
    cout << "Girdiğiniz sayı çift bir sayıdır: " << id << "\n";
    cout << "Sayının 2 katı: " << 2 * id;
  }

  return 0;
}

Çıktı:

Bir int deÄŸer giriniz: 35
Girdiğiniz sayı tek bir sayıdır: 35
Sayının 3 katı: 105

5)

#include <iostream>

using namespace std;

int main(void)
{
  int id;

  cout << "Bir int deÄŸer giriniz: ";
  cin >> id;

  if(id > 100) { // 1
     cout << "Girilen sayı 100'den büyüktür!" << "\n"; // 2
     if(id % 2 == 0) { // 3
        cout << "Girilen sayı çift bir sayıdır!" << "\n"; // 4
        if (id<=150) cout << "Girilen sayı 100-150 arasındadır!"; // 5
        else cout << "Girilen sayı 150'den büyüktür!"; // 6
     }
     else cout << "Girilen sayı tek bir sayıdır!"; // 7
  }
  else { // 8
     if(id == 100) cout << "Girilen sayı 100'dür!"; // 9
     else cout << "Girilen sayı 100'den küçüktür!"; // 10
  }

  return 0;
}

Çıktı:

Bir int deÄŸer giriniz: 398
Girilen sayı 100'den büyüktür!
Girilen sayı çift bir sayıdır!
Girilen sayı 150'den büyüktür!

Kaynak

Bu yazımızda operatörlere değineceğiz. Operatörler değişkenler ve değerler üzerinde işlem yapmak için kullanılırlar. Aşağıda değineceğimiz operatörler belirtilmiştir:

  • İliÅŸkisel operatörler
  • Mantıksal operatörler
  • Aritmetik operatörler
  • Bitsel operatörler

İlişkisel Operatörler

Koşul ifadelerini yazarken farklı değerleri karşılaştırmak için ilişkisel operatörler, ilişkisel ifadeleri birleştirmek için ise mantıksal operatörler kullanılır. Aşağıdaki tabloda ilişkisel operatörler listelenmektedir.

İlişkisel Operatörler

İlişkisel Operatörler

İliÅŸkisel operatörlerle yazdığımız ifadelerin sonucu, bool deÄŸeri olan true veya false olacaktır. ÖrneÄŸin aÅŸağıdaki koÅŸul ifadesi “x deÄŸeri y deÄŸerinden büyüktür” önermesini ifade eder. Bu önerme doÄŸru ise true, yanlış ise false deÄŸerini döndürür.

x > y

== operatörünü atama operatörü (=) ile karıştırmamak gerekir. == operatörü eşitlik kontrolü yapar. = operatörü ise sağdaki değişkeni veya değeri soldaki değişkene atar. Örneğin:

x == 5  // x değişkeni 5'e eşit ise true, değilse false döndürür
x = 5;  // x değişkenine 5 değeri atanır

Örnek 1

#include <iostream>
using namespace std;

int main() {
   int x = 5;
   if(x == 5){
       cout << "x = " << x;
   }
   else{
       cout << " x deÄŸeri 5 deÄŸil";
   }
   return 0;
}

Bu örnekte x deÄŸiÅŸkeni 5’e eÅŸit olduÄŸu için if yapısı true dönecektir. Bundan dolayı çıktı:

x = 5

Fakat x, 5’ten farklı bir sayı olsaydı if koÅŸulu false dönecekti ve else yapısının içine girecekti. Mesela:

#include <iostream>
using namespace std;

int main() {
   int x = 7;
   if(x == 5){
       cout << "x = " << x;
   }
   else{
       cout << " x deÄŸeri 5 deÄŸil";
   }
   return 0;
}

Bu örnekte x’in deÄŸeri 7’dir. Bu nedenle if koÅŸulu saÄŸlanmaz ve else yapısının içine girer ve çıktı:

x deÄŸeri 5 deÄŸil

Örnek 2

#include <iostream>

using namespace std;

int main() {
   int x = 7;
   int y = 10;

   if(x > y){
       cout << "x, y'den büyük";
   }
   else{
       cout << "y, x'den büyük ";
   }
   return 0;
}

Bu örnekte iki tane deÄŸiÅŸken vardır ve bu deÄŸiÅŸkenleri birbiri ile karşılaÅŸtırıyoruz. x deÄŸiÅŸkeninin deÄŸeri 7 olarak atanmıştır. Aynı ÅŸekilde y deÄŸiÅŸkeninin deÄŸeri de 10 olarak atanmıştır. if yapısında x deÄŸiÅŸkeninin y deÄŸiÅŸkeninden büyük olması durumunda TRUE döndürecektir ve çıktı olarak “x, y'den büyük” yazdırılır. Fakat bizim örneÄŸimizde x deÄŸiÅŸkeni, y deÄŸiÅŸkeninden küçük olduÄŸu için if koÅŸulu FALSE dönecektir ve else yapısının içine girecektir ve program çıktısı aÅŸağıdaki gibi olacaktır:

y, x'den büyük

Mantıksal Operatörler

İlişkisel ifadeleri birleştirmek için mantıksal operatörleri kullanmamız gerektiğine değinmiştik. Birleştirme işlemi için kullandığımız mantıksal operatörler aşağıda belirtilmiştir.

Mantıksal Operatörler

Mantıksal Operatörler

Örnek 1

#include <iostream>

using namespace std;

int main() {
   int x = 7;
   int y = 10;

   if(x == 7 && y == 10){
       cout << "x = " << x << ",y = " << y;
   }
   else{
       cout << "x != " << x << ",y != " << y;
   }
   return 0;
}

Bu örnekte x değişkeninin ve y değişkeninin de koşulu sağlaması halinde if koşulu TRUE olacaktır. Eğer bu değişkenlerden biri koşulu sağlamaz ise FALSE olacaktır ve else yapısının içerisine girecektir.

Çıktı:

x = 7,y = 10

Örnek 2

#include <iostream>

using namespace std;

int main() {
   int x = 10;
   int y = 10;

   if(x == 7 || y == 10){
       cout << "x = " << x << ",y = " << y;
   }
   else{
       cout << "x != " << x << ",y != " << y;
   }
   return 0;
}

Bu örnekte, x deÄŸiÅŸkeninin deÄŸeri 10’dur. if yapısında x==7 koÅŸulu doÄŸru deÄŸildir. Fakat y==10 koÅŸulu saÄŸlanmaktadır ve kullanılan operatör “veya ( || )” operatörü olduÄŸu için içlerinden birinin koÅŸulu saÄŸlaması yeterli olacaktır. Bu nedenle if koÅŸulu TRUE olur. FALSE olabilmesi için iki koÅŸulun da saÄŸlanmaması gerekir.

Çıktı:

x = 10,y = 10

Aritmetik Operatörler

Aritmetik operatörler toplama, çıkarma, çarpma, bölme, mod alma gibi matematiksel işlemleri yapmamızı sağlayan operatörlerdir.

Aritmetik Operatörler

Aritmetik Operatörler

Örnek

#include <iostream>

using namespace std;

int main() {
   int x = 15;
   int y = 5;

   cout << "x+y = " << x+y << endl;
   cout << "x-y = " << x-y << endl;
   cout << "x*y = " << x*y << endl;
   cout << "x/y = " << x/y << endl;
   cout << "x%y = " << x%y << endl;

   return 0;
}

Çıktı:

x+y = 20
x-y = 10
x*y = 75
x/y = 3
x%y = 0

x deÄŸiÅŸkeni, y deÄŸiÅŸkeninin katı olduÄŸu için mod deÄŸeri 0’dır.

Bitsel Operatörler

Bitsel operatörler bitler üzerinde çalışır ve bit bit işlemler gerçekleştirmemiz gerektiğinde kullanırız.

Bitsel Operatörler

Bitsel Operatörler

Örnek

#include <iostream>

using namespace std;

int main() {
   int x = 3;
   int y = 5;
   int z = 2;

   cout << "x&y = " << (x&y) << endl;
   cout << "x|y = " << (x|y) << endl;
   cout << "x^y = " << (x^y) << endl;
   cout << "x<<z = " << (x<<z) << endl;
   cout << "x>>z = " << (y>>z) << endl;

   return 0;
}

Çıktı:

x&y = 1
x|y = 7
x^y = 6
x<<z = 12
x>>z = 1

Kaynaklar


Stack(Yığın)

Stack(yığın), aynı türden verilerin bulunduÄŸu lineer(doÄŸrusal) bir veri yapısıdır. Stack, Son Giren İlk Çıkar (Last In First Out - LIFO) ÅŸekilinde çalışır yani stack'a eklenen son ögenin ilk kaldırıldığı anlamına gelir. 



Last In First Out (LIFO):

Bu strateji, son eklenen ögenin ilk çıkarılacağını belirtir. Gerçek hayattan bir örnek olarak üst üste yerleştirilmiş tabak yığını düşünülebilir. En son koyduğumuz tabak en üsttedir ve en üstteki tabağı çıkardığımızda, en son konan tabak ilk çıkar diyebiliriz.


Eğer en alttaki tabağı istiorsak, önce üstteki tüm tabakları çıkartmamız gerekir. Stack(yığın) veri yapısı tam olark böyle çalışır.

Stack LIFO Prensibi

Programlama terimlerinde, bir öğeyi stack'ın üstüne koymaya push, bir öğeyi kaldırmaya ise pop denir.


Görselde, 3. öğe en sonda kalmasına rağmen, ilk olarak kaldırılmıştır.

Stack'ın Temel İşlemleri

Bir stack üzerinde farklı eylemler gerçekleştirmemizi sağlayan bazı temel işlemler vardır.

push: Bir stack'ın üstüne bir eğe ekler
pop: Bir stack'ın tepesinden bir öğeyi kaldırma
IsEmpty: Stack'ın boş olup olmadığını kontrol eder
IsFull: Stack'ın dolu olup olmadığını kontrol eder
peek: Üst öğenin değerini kaldırmadan alma

Stack Türleri

Register Stack(Kayıt Yığını)

Bu tür bir stack aynı zamanda bellek biriminde bulunan bir bellek öğesidir ve yalnızca az miktarda veriyi iÅŸleyebilir. Register stack'nın boyutu belleÄŸe kıyasla çok küçük olduÄŸundan, register stack'nın yüksekliÄŸi her zaman sınırlıdır. 

Memory Stack(Bellek Yığını)

Bu tür bir stack, büyük miktarda bellek verisini işleyebilir. Memort stack'nın yüksekliği, büyük miktarda bellek verisi kapşadığından esnektir.

Stack Uygulaması

1. Dizi Kullanarak

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

// stack'ı temsil edecek bir struct
struct Stack{
int top;
unsigned capacity;
int* array;
};

// verilen kapasitede bir stack oluşturma. Stack boyutu 0 olarak başlatılır
struct Stack* createStack(unsigned capacity){
struct Stack* stack = (struct Stack*) malloc(sizeof(struct Stack));
stack->capacity = capacity;
stack->top = -1;
stack->array = (int*) malloc(stack->capacity*sizeof(int));
return stack;
}

// top son indekse eşit olduğında stack dolu
int isFull(struct Stack* stack){
return stack->top == stack->capacity - 1;
}

// top -1'e eÅŸit olduÄŸunda stack boÅŸtur
int isEmpty(struct Stack* stack){
return stack->top == -1;
}

// Stack'a bir öğe ekleme, top'u 1 artırır
void push(struct Stack* stack,int item){
if(isFull(stack)) return;
stack->array[++stack->top] = item;
printf("%d stack'a eklendi\n",item);
}

// Stack'tan bir öğe kaldırma, top 1 azaltılır.
int pop(struct Stack* stack){
if (isEmpty(stack)) return INT_MIN;
return stack->array[stack->top--];
}

// üst kısmı çıkarmadan stack'ı döndürme
int peek(struct Stack* stack){
if(isEmpty(stack)) return INT_MIN;
return stack->array[stack->top];
}

int main(){
struct Stack* stack = createStack(5);
push(stack,10);
push(stack,40);
push(stack,20);
push(stack,50);

printf("%d stack'tan kaldirildi\n",pop(stack));
return 0;
}
Çıktı:


Dizi Kullanmanın Avantajları:

  • Uygulaması kolay.

Dizi Kullanmanın Dezavantajları:

  • Dinamik deÄŸildir, yani çalışma zamanında ihtiyaca göre büyüyüp küçülmez.
  • Stack'ın toplam boyutu önceden tanımlanır.

2. Linked List Kullanarak

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

// stack'ı temsil edecek bir struct
struct StackNode{
int data;
struct StackNode* next;
};

struct StackNode* newNode(int data){
struct StackNode* stackNode = (struct StackNode*) malloc(sizeof(struct StackNode));
stackNode->data = data;
stackNode->next = NULL;
return stackNode;
}

int isEmpty(struct StackNode* root){
return !root;
}

void push(struct StackNode** root, int data){
struct StackNode* stackNode = newNode(data);
stackNode->next = *root;
*root = stackNode;
printf("%d stack'a eklendi\n",data);
}

int pop(struct StackNode** root){
if(isEmpty(*root)) return INT_MIN;
struct StackNode* temp = *root;
*root = (*root)->next;
int popped = temp->data;
free(temp);

return popped;
}

int peek(struct StackNode* root){
if(isEmpty(root)) return INT_MIN;
return root->data;
}

int main(){
struct StackNode* root = NULL;

push(&root,10);
push(&root,40);
push(&root,20);
push(&root,50);

printf("%d stack'tan kaldirildi\n",pop(&root));
printf("En ustteki eleman %d\n", peek(root));

return 0;
}
Çıktı:



Linked List Kullanmanın Avantajları:

  • Dinamiktir, yani çalışma zamanındaki ihtiyaçlara göre büyüyebilir ve küçülebilir.


Linked List Kullanmanın Dezavantajları:

  • Pointer'ların dahil olması nedeniyle ekstra bellek gerektirir.
  • Stack içinde rastgele eriÅŸim mümkün deÄŸildir.


Kaynaklar:
https://www.geeksforgeeks.org/introduction-to-stack-data-structure-and-algorithm-tutorials/
https://www.digitalocean.com/community/tutorials/stack-in-c
https://www.programiz.com/dsa/stack
https://www.tutorialspoint.com/data_structures_algorithms/stack_program_in_c.htm
 EN:
This article, we converted a 2D array to a 1D array in the c programming language. We did this using a for loop.

TR:
Bu yazımızda, c programlama dilinde 2D diziyi 1D diziye dönüştürdük. Bu işlemi for döngüsü kullanarak gerçekleştirdik.
#include <stdio.h>
#define m 3
#define n 4
int main() {
int arr1d[m*n];
int arr[m][n]={{1,3,4,6},
{4,7,8,9},
{3,5,8,1}};
printf("2D arry:\n");
for(int i =0;i<m;i++){
for(int j = 0; j<n; j++){
printf("%d ",arr[i][j]);
}
printf("\n");
}
printf("\n");
printf("1D arry:\n");
for(int i =0;i<m;i++){
for(int j = 0; j<n; j++){
arr1d[i*n+j]=arr[i][j];
}
}
for(int i = 0; i<m*n; i++){
printf("%d ",arr1d[i]);
}
return 0;
}