スタックをCで

やっぱり世の中はCでできてるんじゃないかという気がして、少しCをやってみた。構造体とかポインタの練習に簡単なスタックを作ってみた。

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

typedef struct {
  int size;
  int ptr;
  int *stk;
} Stack;

int Allocate(Stack *s, int size){
  s->ptr = 0;
  if((s->stk = calloc(size, sizeof(int))) == NULL)
    return -1;
  s->size = size;
  return 0;
}

int FreeStack(Stack *s){
  s->size = 0;
  free(s->stk);
}

int ShowStack(Stack *s){
  int i;
  for(i = 0; i < s->size; i++){
    printf("stack[%2d]: %3d\n",i,s->stk[i]);
  }
}

int Push(Stack *s, int i){
  if(s->ptr < s->size){
    s->stk[s->ptr] = i;
    s->ptr++;
  }else{
    puts("cannot push any more");
    return -1;
  }
}

int Dup(Stack *s){
  int i, *ptr = &s->stk[s->ptr];

  if(s->ptr < s->size){
    i = *(--ptr);
    *(++ptr) = i;
    s->ptr++;
  }else{
    puts("cannot dup any more");
    return -1;
  }
}

int main (int argc, char *argv[]){
  Stack s;
  int i, size;

  if(argc <= 1){
    puts("need an argument");
    return -1;
  }else{
    size = atoi(argv[1]);
  }

  if(Allocate(&s, size) == -1){
    puts("cannot allocate stack area");
    return 1;
  }
  for(i = 11; i < 15; i++){
    Push(&s, i);
    Dup(&s);
  }
  ShowStack(&s);
  FreeStack(&s);
}

実行結果は、こんな感じ。

$ gcc -o stack stack.c ; ./stack 10
stack[ 0]:  11
stack[ 1]:  11
stack[ 2]:  12
stack[ 3]:  12
stack[ 4]:  13
stack[ 5]:  13
stack[ 6]:  14
stack[ 7]:  14
stack[ 8]:   0
stack[ 9]:   0
$ gcc -o stack stack.c ; ./stack 6
cannot push any more
cannot dup any more
stack[ 0]:  11
stack[ 1]:  11
stack[ 2]:  12
stack[ 3]:  12
stack[ 4]:  13
stack[ 5]:  13
$ 

これだけ動かすだけでも苦労した。そして、スタックの上から2つを入れ替えるswap関数を作ろうとして、ポインタの使い方がよく分からなくなった。いや、もともと分かってないんだけど。

#include <stdio.h>

int main(void){
  char *ptr;
  char x[] = "This test is dead simple";

  ptr = x;
  ptr += 2;

  printf("%c%c\n",*ptr, *(ptr + 1));
}

とやると、結果は「is」となる。3文字め(*ptr)と4文字目(*(ptr + 1))が表示されている。ところが、

printf("%c%c\n",*ptr, *(ptr++));

とやると、「si」と逆順になる。さらに、

printf("%c%c\n",*ptr, *(++ptr));

とやると、「ss」となってしまう。まだしも、ptr++とやった場合に結果が「ii」なら意味が分かるんだけどなぁ。根本的に分かってない感じが強い。