pit-rayの備忘録

ゲームやソフトウェアの開発にて得た知識や制作活動の途中経過をまったり書いていくブログ。

構造体へのポインタの初期化

今回もC言語についての備忘録になります。

 

今回のトピックは

構造体へのポインタの初期化

です。(タイトルにもありますが)

 

これは初歩的なミスです。

しかし、私は初心者故、最近こいつとバトルしました。

まず、悪い例のソースコードはこちら。

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

typedef struct _Position {
    int x ;
    int y ;
} Pos ;

void AddOne( Pos *hoge  ) {
    hoge->x ++ ;
    hoge->y ++ ;
    return ;	
}

int main( void ) {

    Pos *temp ;

    temp->x = 10 ;
    temp->y = 20 ;
    
    printf( "BeforePosition(%d,%d)", temp->x, temp->y ) ;

    AddOne( temp ) ;
	
    printf( "AfterPosition(%d,%d)", temp->x, temp->y ) ;

    return ;
}

 

今回私がVisual Studioにて吐かれたエラーは

***.exe の0x0164536Eで初回の例外が発生しました: 0xC0000005: 場所 0x00000000 を読み込み中にアクセス違反が発生しました。

というものです。

 

調べるとこのエラーは大概、初期化されていないポインタを使用した場合に吐かれるらしいです。

これは

ポインタの定義だけではメモリが確保されない

ことが原因です。

 

その為、

一度メモリを確保してゼロクリア

すれば初期化できます

メモリを動的確保をしているため、最終的に使い終わったらメモリを開放しなくてはいけません。

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

typedef struct _Position {
    int x ;
    int y ;
} Pos ;

void AddOne( Pos *hoge  ) {
    hoge->x ++ ;
    hoge->y ++ ;
    return ;	
}

int main( void ) {

    Pos *temp ;
	
    temp = ( Pos * ) malloc( sizeof( Pos ) ) ;
    memset( temp, 0, sizeof( Pos ) ) ;

    temp->x = 10 ;
    temp->y = 20 ;
    
    printf( "BeforePosition(%d,%d)", temp->x, temp->y ) ;

    AddOne( temp ) ;
	
    printf( "AfterPosition(%d,%d)", temp->x, temp->y ) ;

    free( temp ) ;
    return ;
}

 

 

この赤字で示した箇所が追加したコードです。

 

数分でぱぱっと書いたソースコードなので誤りがあったらご指摘ください。

 

以上、備忘録でした。

ポインタ型の構造体を定義するときはメモリを確保して初期化するようにしましょう。

 

大学受験で病み気味

今日も終わりへと近づいて来ました23:50。

実は高校生である私は偏差値10くらい上の大学を志望してるのである。

無謀である。

 

というのは冗談で、結構イケる自信がある。

 

勿論点数を取れてないのは事実だが、内容が分からないわけではなく、単に定着してないだけだ。

これは落ちる受験生の定番の決め台詞だろうか。

 

まぁいい。

勉強するしかない。

 

あぁ、開発の時間が無くなる...(´;ω;`)

 

とはいうものの、ここ2年、リファクタリングと3DCGに没頭していて、あっという間に過ぎた。正直、個人開発つらみ。

 

そんなこんなで一切需要がない記事であった。

おやすみ。

 

malloc()+memset()とcalloc() ゼロクリアする場合における違い

今回は開発していて気になったことがあったのでググってみました。

言語はCです。

 

最初の記事にも書いたのですが、私自身、プログラミング歴が長いわけではないため、信憑性はかなり低いものとなっております。

ネットサーフィンの基本ですが、より意識して情報の取捨選択をお願いします。

 

 

 

まず、今回気になったことは

malloc()+memset()によるゼロクリアとcalloc()によるゼロクリアは何が違うのだろうか

ということです。

 

まず、それぞれの関数の定義等を見ていきましょう。

 

メモリ確保を行う関数。stdlib.hに定義されている。

定義:void *malloc(size_t size)

戻り値:確保したメモリの先頭アドレス

参考:malloc - Wikipedia

 

  • memset

指定したメモリブロックから指定したバイト数の範囲に指定した文字データを書き込む関数。string.hに定義されている。

つまりは、指定した範囲を指定した文字で埋める関数です。

今回はこの関数を利用して上記のmalloc関数で確保したメモリをmemset関数で初期化(ゼロクリア)するということです。(このことを以下malloc()+memset()と略す )

定義:void *memset(void *s, int c, size_t)

戻り値:sの先頭アドレス

参考:memset - Wikipedia

 

  • calloc

メモリの確保とその初期化(ゼロクリア)する関数。stdlib.hに定義されている。

これはmalloc関数にゼロクリア機能が付いたもの。

定義:void *calloc(size_t nelements, size_t bytes)

戻り値:確保したメモリの先頭アドレス

参考:malloc-関連する関数 - Wikipedia

 

ここでmemset()の初期化処理とcalloc()の初期化処理は何が違うのかということが気になったわけです。

その為、ググってみたところ、以下のようなページがありました。

c - Why malloc+memset is slower than calloc? - Stack Overflow

ここのAnswersに以下のように書かれていたため、高校生レベルの英語力である私が軽く適当に訳してみました。(weblioGoogle翻訳を使用)

 The short version: Always use calloc() instead of malloc()+memset(). In most cases, they will be the same. In some cases, calloc() will do less work because it can skip memset() entirely. In other cases, calloc() can even cheat and not allocate any memory! However, malloc()+memset() will always do the full amount of work.

 

 

要約文:常にmalloc()+memset()の代わりにcalloc()を使用してください。殆どの場合、それらは同じものとして機能するでしょう。場合によってはcalloc()は完全にmemset()をスキップし得るので、より少ない仕事をするでしょう。 (calloc()はmemset()の簡易版的な意味合いだろうか)他の場合では、calloc()は少しもメモリを割り当てることが出来ず、誤魔化すことすらあり得ます。しかしながら、malloc()+memset()は全ての仕事量をこなします。

 この訳は全く持って正しいものではないので、他サイトなどに転載しないようにご協力お願いします。ここでは大体の意味を掴むために訳しております。

 

つまり、memset()のほうがcalloc()よりも確実にゼロクリアを行うといった感じでしょうか。

 

しかし、上記の参考サイトの質問者が仰っている通り、calloc()のほうがmemset()+malloc()よりも高速らしいです。

この件に関しての記事がありました。

malloc+memsetとcallocの違いについて

 

私の記事よりも詳しく書かれています。

もう少し深いところを知りたい場合、是非アクセスしてみてください。

 

結果的に言いますと、どちらがイイとは言えません。

どちらもそれぞれメリット・デメリットがあるみたいです。

素人の私にしてみるとお腹一杯です...(;´Д`)

 

まとめると

Q -ゼロクリアするうえでのmemset()とcalloc()の違いは?

A -「確実性」memset() >calloc()

  「速度面」memset()<calloc()

といった感じでしょうか。

 

何かこの記事にご不明な点や変な個所がありましたら、コメントにて指摘して頂けると幸いです。また、私は初心者みたいなものなので、意見など書いていただけると助かります。

何度も言いますが...

あくまで備忘録であることをお忘れなく。

それではまたの機会に会いましょう。

☆。.:*:・'゜ヽ( ´ー`)ノ まったね~♪

 

ブログ開設しました

どうも初めまして。pit-rayです。

 

これからこのブログの管理人兼、執筆者として記事を書かせていただきます。

 

私自身、プログラミングやゲーム制作など経験が豊富というわけではなく、完全趣味程度に行っています。プログラミングなんかも独学です。

その為、このブログの記事の信憑性は極めて低いものになっておりますことをご了承ください。

 

ご要望や意見などは以下からしていただくと幸いです。

「管理人へのアクセス方法」

 

①ブログのコメント

正直これが一番有り難い。

ブログも活発になって最終的にアフェリエイト収入も得られるし...(ボソ///

 

TwitterのリプorDM

 

Twitterボタン
Twitterブログパーツ

 

恐らく一番反応するであろうアクセス方法。

取り敢えず、フォローしておけばいいと思う。

 

メールアドレスなどは特に用意していませんが、知りたい方はコメントしていただけると幸いです。

 

最後に

そこまで長い文にはしないようにしますので、今後ともちらっと見ていただけると嬉しいです。