Standart C Programlama Dili


EK F: SEÇİLMİŞ PROBLEMLERE YANITLAR

Bu ekte, her bölümün sonunda verilen problemlerden bazıları için yanıtlar verilmiştir. Bazı problemler için değişik çözümler de söz konusu olabilir. Burada ilk sayı bölümü, ikinci sayı ise problemi belirtir.

1.1. Şunu deneyin:

int main (void)
{
  int entry = 0;
  return entry;
}

1.4. Evet, x=5; deyimine eşdeğerdir.

1.5. Evet, boş bir blok deyimidir.

1.6.


scanf("%f", &x);
printf("%d", (int)x);

2.2.

switch (yas)
  case 16 : printf("");

2.4.

#include <stdio.h>
int main (void)
{
  unsigned  i, n;
  scanf("%u", &n);
  for (i=1; i<=n; i++)
    printf("%u\t%g\n", i*i, 1.0/i);
  return 0;
}

2.6.

#include <stdio.h>
int main (void)
{
  int  p, c, i;
  c = p = getchar();
  i = 1;
  while (c!=EOF) {
    c = getchar();
    if (c==p)
      i++;
    else {
      if (i==3)
        printf("%c ", p);
      p = c;
      i = 1;
    } /* else */
  } /* while */
  return 0;
}

2.8. Satır 32’deki do’yu uygun bir şekilde while’a çevirin.

2.9.

#include <stdio.h>
#include <float.h>
#define  b  10.0
int main (void)
{
  double  x, d, log;
  int     i, di, xi, xj;
  /* başlıklar */
  printf("       ");
  for (xj=0; xj<10; xj++)
    printf("%+9.2lf", xj/100.0);
  printf("\n      +");
  for (xj=0; xj<10; xj++)
    printf("  -------");
  printf("\n");
  for (xi=10; xi<100; xi++) {
    printf ("%5.2lf |", xi/10.0);
    for (xj=0; xj<10; xj++) {
      x = xi/10.0 + xj/100.0;
      /* log_b(x) hesaplama */
      d = 1.0;
      log = 0.0;
      for (i=1; i<=DBL_DIG; i++) {
        x = x*x*x*x*x;
        x *= x;
        for (di=0; x>b; x/=b, di++)
          ;
        d *= 10.0;
        log += di/d;
      } /* for i */
      printf ("%9.5lf", log);
    } /* for xj */
    printf ("\n");
  } /* for xi */
}

3.1. Gösterge aritmetiğine karşılık tamsayı aritmetiği. Bu sistemde short’un iki bayt uzunluğunda olduğunu anlarız.

3.2.

#include <stdio.h>
int main (void)
{
  printf("%s-doldurma\n", (-10>>1<0)?"isaret":"sifir");
  return 0;
}

3.3.

#include <stdio.h>
int main (void)
{
  unsigned  n, b;
  scanf("%u", &n);
  for (b=0; n!=0; n>>=1)
    b += n&1;
  printf("%d bit\n", b);
  return 0;
}

3.4. Eğer a ve b aynı tipten ise içeriklerini değiştirir.

3.7. (a) değişkenlerin boş küme olarak ilklenmesi;
(b) n sayısının kume1’e eklenmesi;
(c) n sayısının kume2’den çıkarılması;
(d) iki kümenin aynı içerikte olup olmadığının denetlenmesi;
(e) iki kümenin bileşimi;
(f) küme farkı;
(g) kume2 veya kume3’te olup da her iki kümede olmayan sayıların kume1’e konması.

4.1. Hayır! Bundan emin olamayız. Çünkü bu, printf fonksiyonu çağrısındaki argümanların hesaplanma sıralarına bağlıdır.

4.2.

int maks (int x, ...)
{
  int maks, *xg;
  for (maks = *(xg=&x); *xg != 0; xg++)
    if (maks < *xg)
      maks = *xg;
  return maks;
}

Tanımda ... (üç nokta) geri kalan parametrelerin sayılarının (ve tiplerinin) belirlenmediği anlamına gelir. Ancak, böyle değişken sayıda argümanlı fonksiyon yazmanın taşınabilir yolu bu değildir. Bunun yerine, aşağıda gösterildiği gibi, stdarg.h standart başlık dosyasında tanımlanmış bulunan va_start, va_arg ve va_end makroları kullanılmalıdır.

#include <stdarg.h>
int maks (int x, ...)
{
  int maks;
  va_list xg;       /* geri kalan argümanlara gösterge */
  va_start(xg, x);  /* ilk isimlendirilmemiş argümana
                     * işaret et */
  for (maks = x; x != 0; x = va_arg(xg,int))
    if (x > maks)
      maks = x;     /* yeni enbüyük */
  va_end(xg);       /* dönmeden önce temizlik yap */
  return maks;
}

4.3. İlklenmemiş otomatik değişkenler belirsiz değerler taşır. Bu, daha önce aynı adreste saklanmış olan bir otomatik değişkenin değeri olabilir.

4.4. Sadece ilk iki register bildirimi dikkate alınır, geri kalanlar auto gibi işlem görürler. Aynı zamanda bir önceki alıştırmaya bakın.

4.5. Girilen satırdaki karakterleri tersten basar.

4.9. Sudoku bulmacalarını çözen program aşağıda verilmektedir:

#include <stdio.h>

int sayi = 0;
int tahta [9][9];

int tahtaTamam (int r, int c, int d)
{
  int rr, cc;

  for (cc = 0; cc < 9; cc++)
    if (tahta[r][cc] == d)
      return 0;
  for (rr = 0; rr < 9; rr++)
    if (tahta[rr][c] == d)
      return 0;
  for (rr = r/3*3; rr < r/3*3+3; rr++)
    for (cc = c/3*3; cc < c/3*3+3; cc++)
      if (tahta[rr][cc] == d)
        return 0;
  tahta[r][c] = d;
  return 1;
}

void cozumyaz (void)
{
  int r, c;

  printf("\n\n\tCOZUM %d\n\n", ++sayi);
  for (r = 0; r < 9; r++) {
    for (c = 0; c < 9; c++)
      printf("%2d", tahta[r][c]);
    printf("\n");
  }
}

void yerlestir (int pozisyon)
{
  int deger, r, c;

  if (pozisyon == 9*9)
    cozumyaz();
  else {
    r = pozisyon / 9;
    c = pozisyon % 9;
    if (tahta[r][c] == 0) {
      for (deger = 1; deger <= 9; deger++)
        if (tahtaTamam(r,c,deger))
          yerlestir(pozisyon+1);
      tahta[r][c] = 0;
    } else
      yerlestir(pozisyon+1);
  }
}

int main (void)
{
  int r, c;
  char t;

  for (r=0; r<9; r++)
    for (c=0; c<9; c++) {
      do
        scanf("%c", &t);
      while (t=='\n' || t==' ');
      tahta[r][c] = (t>='1' && t<='9') ? (t-'0') : 0;
    }
  yerlestir(0);
  printf("\n\n%d adet cozum bulundu.\n", sayi);
  return 0;
}

4.10. envp dizisinin sonunu boş gösterge kontrolü yaparak bulabiliriz:

#include <stdio.h>
int main (int argc, char *argv[], char *envp[])
{
  int i;
  printf("Merhaba, benim ismim %s.\n", argv[0]);
  printf("Argumanlarim sunlar");
  for (i=1; i<argc; i++)
    printf(", %s", argv[i]);
  printf(".\nOrtam degiskenlerim de sunlar:\n");
  for (i=0; envp[i]!=NULL; i++)
    printf("%s\n", envp[i]);
  return 0;
}

5.1. (a) sıfır, yani ilk sayıcı ve (b) belirsiz bir değer.

5.4.

int *tamsayıya gösterge,
int *[3]tamsayıya 3 göstergeden oluşan dizi,
int (*)[3]3 tamsayıdan oluşan diziye gösterge,
int *(float)argümanı float olan ve int’e gösterge döndüren fonksiyon,
int (*)(void)argümanı olmayan ve int döndüren fonksiyona gösterge.

5.5. a[i,j] ile a[(i,j)] eşdeğerdir, bu da a[j]’ye, yani bir göstergeye eşdeğerdir.

5.6. x dizi olmasına karşın, a bir göstergedir.

5.8. a değişmez bir göstergedir; bundan sonra hep &y’yi göstermek zorundadır. Fakat gösterdiği yer, yani y içindeki bilgi değiştirilebilir.

b de değişmez bir göstergedir, bunun yanında gösterdiği yer, yani x de program tarafından değiştirilemez. Buna rağmen, bu yer program dışındaki bir süreç tarafından değiştirilmektedir. Yani b’nin gösterdiği yeri program değiştiremez, sadece okuyabilir.

6.1.

typedef int * gosterge;

ile

#define gosterge int *

birbirine benzemektedir, ama

typedef int dizi[N];

#define ile ifade edilemez, onun için typedef tercih edilir.

6.2.

#define dok(x) printf("x = %d\n", x)

Eğer Standarda uygun bir önişlemciniz varsa, o zaman aşağıdakini kullanın:

#define dok(x) printf(#x " = %d\n", x)

Makroyu, örneğin dok(2 * 3 + 4); şeklinde çağırabilirsiniz.

7.9. Sistemimizde eğer unix-benzeri bir ortamda derleme yapılıyorsa, __unix__ şeklinde bir makro tanımlı gelir. Eğer bu makro tanımsızsa, başka bir işletim sistemi (örneğin, Microsoft Windows) altında derleme yaptığımızı anlarız. Aşağıdaki, fonksiyon, Linux dahil, unix-benzeri sistemlerde ve Windows sistemlerinde doğru kodu çalıştıracaktır.

#include <stdlib.h>
void temizle (void)
{
#ifdef __unix__
  system("clear");
#else
  system("CLS");
#endif
}

8.1.

#include <stdio.h>
#include <time.h>
#include <locale.h>

int main (int argc, char *argv[])
{
  int ay, yil;
  struct tm yz;
  char cikti[20];

  setlocale(LC_ALL, "");
  if (argc!=3 || sscanf(argv[1], "%d", &ay)!=1 ||
      sscanf(argv[2], "%d", &yil)!=1) {
    fprintf(stderr, "Kullanim: %s ay yil\n", argv[0]);
    return 1;
  }
  yz.tm_year = yil - 1900;
  yz.tm_mon  = ay - 1;
  yz.tm_hour = 12;
  yz.tm_min  = yz.tm_sec = 0;
  yz.tm_isdst = -1;
  for (yz.tm_mday=1; yz.tm_mday<=31; yz.tm_mday++) {
    if (mktime(&yz)==-1 || yz.tm_mon!=(ay-1))
      break;
    if (strftime(cikti,sizeof cikti,"%a %d %b %Y",&yz)!=0)
      puts(cikti);
  }
  return 0;
}