ページ 11

配列のアドレスに対する加算について

Posted: 2012年10月07日(日) 22:52
by へっくす
夜分に失礼します.
C言語の勉強をしているものです.
アドレスの勉強中にふと疑問に思ったことがあったので,
テスト用にプログラムを作成しました.
以下のプログラムを実行した結果になります.

char:h,hex(68),address:6f16db23,
char:o,hex(6f),address:6f16db24,
char:g,hex(67),address:6f16db25,
char:e,hex(65),address:6f16db26,
char:,hex(0),address:6f16db27,
val: 123,address:6f16db18,
val: 456,address:6f16db1c,
size:8
size:1
size:8
size:4

配列の先頭アドレスに1を加算した結果がchar配列とint配列で違いがでました.
char1つ1バイト,int1つ4バイトなのでこのような結果になるとは思うのですが,
それぞれアドレスに1ずつ加算しているにも関わらず,なぜ違いがでるのでしょうか?
6f16db18に1を加算したら6f16db19になるのではないかと思います.

コード:

#include<stdio.h>

int main(void) {

  char hoge[5] = "hoge";
  int baz[2] = {123,456};
  int i;

  for(i = 0; i < 5; i++) {
    printf("char:%1c,hex(%x),address:%x,\n", *(hoge + i), *(hoge + i), hoge + i);
  }

  for(i = 0; i < 2; i++) {
    printf("val:%4d,address:%x,\n", *(baz + i), baz + i);
  }

  printf("size:%d\n", sizeof(char*));
  printf("size:%d\n", sizeof(char));

  printf("size:%d\n", sizeof(int*));
  printf("size:%d\n", sizeof(int));

  return 0;
}

Re: 配列のアドレスに対する加算について

Posted: 2012年10月07日(日) 23:04
by へにっくす
へっくす さんが書きました:char1つ1バイト,int1つ4バイトなのでこのような結果になるとは思うのですが,
・・・答えでてるじゃん 笑

配列の場合、連続した領域だから、
charの配列だったらcharのサイズ×配列の数、
intの配列だったらintのサイズ×配列の数ぶん
メモリを確保してることになります
だから一つ増やすたびにアドレスはそのサイズ分増えるのです。
このことは
*(p + i)

p
と置き換えることが可能なことからも分かるのでは?

Re: 配列のアドレスに対する加算について

Posted: 2012年10月07日(日) 23:23
by へっくす
*(p + i)とpは一緒ですね笑
何がなんでも1バイトずつ進めるとしたら*(p | 1)とすると良いのでしょうか?
コンパイルしてないので,なにも言えませんが
へにっくす さんが書きました:
へっくす さんが書きました:char1つ1バイト,int1つ4バイトなのでこのような結果になるとは思うのですが,

・・・答えでてるじゃん 笑

配列の場合、連続した領域だから、
charの配列だったらcharのサイズ×配列の数、
intの配列だったらintのサイズ×配列の数ぶん
メモリを確保してることになります
だから一つ増やすたびにアドレスはそのサイズ分増えるのです。
このことは
*(p + i)

p
と置き換えることが可能なことからも分かるのでは?

Re: 配列のアドレスに対する加算について

Posted: 2012年10月08日(月) 02:44
by nil
pをcharポインタへキャストすればいいかと

コード:

*((char*)p+i)

Re: 配列のアドレスに対する加算について

Posted: 2012年10月08日(月) 07:51
by みけCAT
へっくす さんが書きました:何がなんでも1バイトずつ進めるとしたら*(p | 1)とすると良いのでしょうか?
pの値が奇数だとうまくいかないと思います。

Re: 配列のアドレスに対する加算について

Posted: 2012年10月08日(月) 10:10
by へっくす
お返事ありがとうございます.
涼雅 さんが書きました:pをcharポインタへキャストすればいいかと

コード:

*((char*)p+i)
charのポインタとしてキャストすることで1byteずつ増やすコードという理解でよろしいでしょうか?

そこで,下記のようなプログラムを作って確認してみました.
intのポインタとしてcharのポインタをキャストしました.
なので,期待する出力としては

コード:

6154ab10,a
6154ab14,e // <-aの4byte先の値
という結果を期待しました.
#アドレスは適当
ですが,実際には

コード:

6154ab10,a
6154ab20,   // <-期待するアドレスと違う!
このような結果になりました.
intのポインタとしてキャストしているにも関わらず,
なぜこのような結果になるのでしょうか?

コード:

#include<stdio.h>

int main(void) {

  int baz[2] = {123,456};
  char hoge[] = "abcdefg";
  int i;

  // increment
  for(i = 0; i < 7; i++) {
    printf("%x,%c\n", hoge + i, *(hoge + i));
  }

  printf("----------------------------------------\n");

  for(i = 0; i < 7; i += 4) {
    printf("%x,%c\n", (int*)hoge + i, *((int*)hoge + i));
  }

  return 0;
}

Re: 配列のアドレスに対する加算について

Posted: 2012年10月08日(月) 10:11
by へっくす
みけCAT さんが書きました:
へっくす さんが書きました:何がなんでも1バイトずつ進めるとしたら*(p | 1)とすると良いのでしょうか?
pの値が奇数だとうまくいかないと思います。
勉強不足で申し訳ありません.
どうして奇数だとうまくいかないのでしょうか?

Re: 配列のアドレスに対する加算について

Posted: 2012年10月08日(月) 10:14
by へっくす
No.6の投稿間違ってますね・・・・

コード:

  for(i = 0; i < 7; i += 1) {
    printf("%x,%c\n", (int*)hoge + i, *((int*)hoge + i));
  }
こうでした.
お騒がせして申し訳ありません.

Re: 配列のアドレスに対する加算について

Posted: 2012年10月08日(月) 11:37
by nil
訂正された時の出力はどうなっていますか?

Re: 配列のアドレスに対する加算について

Posted: 2012年10月08日(月) 16:35
by へっくす
このようになりました.

コード:

64c8ab10,a
64c8ab14,e
64c8ab18,{
64c8ab1c,##
           64c8ab20,
64c8ab24,
64c8ab28,A
余計な部分が出てますが,intのポインタとしてキャストすることで
1を足す=アドレスから4バイト先のアドレスを指す
ということを確認できました.
涼雅 さんが書きました:訂正された時の出力はどうなっていますか?

Re: 配列のアドレスに対する加算について

Posted: 2012年10月08日(月) 21:19
by みけCAT
へっくす さんが書きました:
みけCAT さんが書きました:
へっくす さんが書きました:何がなんでも1バイトずつ進めるとしたら*(p | 1)とすると良いのでしょうか?
pの値が奇数だとうまくいかないと思います。
勉強不足で申し訳ありません.
どうして奇数だとうまくいかないのでしょうか?
|はビットOR演算子であり、 (p | 1)はpの一番下のビットを1にした数になります。
pが奇数の場合、一番下のビットは最初から1なので、p == p | 1となります。

コード:

#include <stdio.h>
 
int main(void) {
        int a=12345;
        printf("%08x\n",a);
        printf("%08x\n",a | 1);
        a=12346;
        printf("%08x\n",a);
        printf("%08x\n",a | 1);
        return 0;
}
http://ideone.com/rHI8R

ちなみに、(gccでは)ポインタに対し|演算子は使えませんでした。

コード:

#include <stdio.h>
 
int main(void) {
        int a=1;
        int* p=&a;
        printf("%p\n",p);
        printf("%p\n",p | 1);
        return 0;
}
http://ideone.com/fT6ZJ

Re: 配列のアドレスに対する加算について

Posted: 2012年10月09日(火) 07:25
by へっくす
お返事ありがとうございます.
確かに奇数だとうまくいきませんね・・・