web-dev-qa-db-ja.com

ポインタを簡潔に宣言して初期化します(つまり、intへのポインタ)

Charへのポインタが与えられると、次のことができます。

char *s = "data";

私が理解している限り、ここでポインタ変数が宣言され、変数とデータの両方にメモリが割り当てられ、後者はdata\0で埋められ、問題の変数はその最初のバイトを指すように設定されます(つまり変数逆参照できるアドレスが含まれています)。それは短くてコンパクトです。

たとえば、intへのポインタが与えられると、次のことができます。

int *i;
*i = 42;

またはその:

int i = 42;
foo(&i); // prefix every time to get a pointer
bar(&i);
baz(&i);

またはその:

int i = 42;
int *p = &i;

それはややトートロジーです。これは小さく、1つの変数を1回使用するだけで許容できます。ただし、複数の変数を複数回使用することはできませんが、コードが乱雑になります。

同じことを乾いて簡潔に書く方法はありますか?彼らは何ですか?問題を完全に回避することを可能にする、プログラミングへのより広い範囲のアプローチはありますか?ポインタをまったく使わない(冗談)のではないでしょうか?

7
user3849273

文字列リテラルはコーナーケースです。静的メモリでのリテラルの作成と、char配列としてのアクセスをトリガーします。以下は、_42_がintリテラルであるにもかかわらず、暗黙的に割り当てられていないため、コンパイルされないことに注意してください。

_int *p = &42;
_

それ以外の場合はすべて、自動メモリまたは動的メモリのいずれであっても、ポイントされたオブジェクトを割り当てる必要があります。

_int i = 42;
int *p = &i;
_

ここで、iは自動変数であり、pはそれを指します。

_int * i;
*i = 42;
_

未定義の振る舞いを呼び出しました。 iは初期化されていないため、メモリ内のランダムな場所を指しています。次に、_42_をこのランダムな場所に割り当てましたが、予測できない結果になりました。悪い。

_int *i = malloc(sizeof *i);
_

ここで、iは、動的に割り当てられたメモリブロックを指すように初期化されます。使い終わったら、free(i)を忘れないでください。

_int i = 42, *p = &i;
_

そして、これが自動変数とそれへのポインターをワンライナーとして作成する方法です。 iは変数であり、pはそれを指します。

編集:あなたは本当にその変数を暗黙的かつ匿名で割り当てたいようです。さて、これがあなたがそれをすることができる方法です:

_int *p = &(int){42};
_

このことは複合リテラルです。これらは自動保存期間(またはファイルスコープで静的)の匿名インスタンスであり、C90以降にのみ存在します(C++には存在しません!)。文字列リテラルとは対照的に、複合リテラルは変更可能です。つまり、_*p_を変更できます。

編集2:完全を期すために 別の回答 (残念ながら間違った説明を提供しました)から着想を得たこのソリューションを追加します:

_int i[] = {42};
_

これにより、自動保存期間を持つ1要素の可変配列が割り当てられます。配列の名前 ポインタ自体ではありませんが は、必要に応じてポインタに減衰します。

ただし、_sizeof i_は「間違った」結果、つまりポインタのサイズ(1 * sizeof(int))ではなく配列の実際のサイズ(sizeof(int*))を返すことに注意してください。ただし、これが問題になることはめったにありません。

15
Quentin
int i=42;
int *ptr = &i;

これは書くことと同じです

int i=42;
int *ptr;
ptr=&i;

これは間違いなく紛らわしいですが、関数呼び出し中には次のように非常に便利です。

void function1()
{
int i=42;
function2(&i);
}

function2(int *ptr)
{
printf("%d",*ptr); //outputs 42
}

ここでは、この紛らわしい表記法を簡単に使用して、関数呼び出し中にポインターを宣言および初期化できます。ポインタをグローバルに宣言し、関数呼び出し中に初期化する必要はありません。両方を同時に行う表記があります。

int *ptr; //declares the pointer but does not initialize it
//so, ptr points to some random memory location
*ptr=42; //you gave a value to this random memory location

これはコンパイルされますが、実際にはポインタを初期化したことがないため、未定義の動作が呼び出されます。

また、

char *ptr;
char str[6]="hello";
ptr=str;

編集:コメントで指摘されているように、これらの2つのケースは同等ではありません。ただし、どちらの場合も、ポインタは「こんにちは」を指します。この例は、これらの両方の方法(helloを指す)でポインターを初期化できることを示すためだけに書かれていますが、確かに両方とも多くの点で異なります。

char *ptr;
ptr="hello";

文字列の名前として、strは実際には文字列の0番目の要素、つまり 'h'へのポインタです。同じことが配列arr []にも当てはまります。ここで、arrには0番目の要素のアドレスが含まれています。

1

配列と考えることもできます、int i[1]={42}ここで、iはintへのポインタです。

0
Luca Rocchi
int * i;
*i = 42; 

未定義の動作を呼び出します。不明なメモリ位置を変更しています。最初にポインタiを初期化する必要があります。

int i = 42;
int *p = &i;

正しい方法です。これで、piを指しており、pが指す変数を変更できます。

同じことを乾いて簡潔に書く方法はありますか?

いいえ。Cには参照渡しがないため、関数で渡された変数を変更する場合はポインターを使用する必要があります。

問題を完全に回避することを可能にする、プログラミングへのより広い範囲のアプローチはありますか?ポインタをまったく使わない(冗談)のではないでしょうか?

あなたがCを学んでいるなら、あなたはポインタを避けることができないので、あなたはそれを正しく使うことを学ぶべきです。

0
haccks