二次元配列のポインタを他のソースファイルで書き換えたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ゆうさく

二次元配列のポインタを他のソースファイルで書き換えたい

#1

投稿記事 by ゆうさく » 7年前

メイン関数で宣言した二次元配列の先頭ポインタを,他のソースファイルで宣言した一次元配列の中身で置き換える方法がわかりません.

-やりたいことのイメージ-
配列a[2][5]={ { 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 }}
配列b[5]= {11,,12, 13, 14, 15}

---配列a[0][0]のアドレスを配列bのアドレスに置き換える---

配列a[2][5]={ { 11, 12, 13, 14, 15 },
{ 6, 7, 8, 9, 10 }}

自分の限界

コード:

/*Main.cpp*/
#include <stdio.h>
#include "Header.h"


int main(void){
	int a[][5] = 
	{
		{ 1, 2, 3, 4, 5 },
		{ 6, 7, 8, 9, 10 }
	};
	

	// aのポインタと中身を表示
	printf("aのアドレス%d\n", a);
	
	printf("a=");
	for (int i = 0; i < 2; i++){
		for (int j = 0; j < 5; j++){
			printf("%d, ", a[i][j]);
		}
		printf("\n");
	}

	// bの中身を出力
	output();


	printf("\n配列aの先頭アドレスを配列bの先頭アドレスで書き換える\n\n");
	// 配列aのポインタを投げる
	setPointer(a);

	
	printf("a=");
	for (int i = 0; i < 2; i++){
		for (int j = 0; j < 5; j++){
			printf("%d, ", a[i][j]);
		}
		printf("\n");
	}


	return 0;
}

コード:

/*Sub.cpp*/

#include <stdio.h>

int *pointer;
int b[] = {11,12,13,14,15};


void setPointer(int p[2][5]){
	p[0][0] = b[0];
	p[0][1] = b[1];
	p[0][2] = b[2];
	p[0][3] = b[3];
	p[0][4] = b[4];
}


void output(){
	printf("bのアドレス = %d\n", b);

	printf("b=");
	for (int i = 0; i < 5; i++){
		printf("%d, ", b[i]);
	}
	printf("\n");
}
こんな感じに一つずつ代入するしか方法はないのでしょうか?
ポインターでポンと代入できた方が,見た目がスッキリして,もっと大きな配列を扱う場合でも処理が重くならないし,bの値を書き換えるたびに代入する必要がなくなる思うので,いいと思うのですが・・・.

あんどーなつ
記事: 171
登録日時: 7年前
連絡を取る:

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#2

投稿記事 by あんどーなつ » 7年前

このサイトの内容が参考になると思います。
(アバター画像がアレですけど・・・)

http://d.hatena.ne.jp/heiwaboke/20091012/1255275804

コード:

int **pointer;
pointer = &a;
pointer = &b;
int i = (*pointer)[1]; // もはや電波ですね
ならうまくいくと思います。

あんどーなつ
記事: 171
登録日時: 7年前
連絡を取る:

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#3

投稿記事 by あんどーなつ » 7年前

すいません、こうしないといけないみたいです。

コード:

int *pointer;
pointer = &(a[0][0]);
pointer = &(b[0]);
int i = pointer[1];

inemaru
記事: 108
登録日時: 7年前

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#4

投稿記事 by inemaru » 7年前

コピーで実現する場合のソース
► スポイラーを表示
最後に編集したユーザー inemaru on 2016年11月17日(木) 00:29 [ 編集 1 回目 ]

inemaru
記事: 108
登録日時: 7年前

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#5

投稿記事 by inemaru » 7年前

コピーで実現する場合のソース
► スポイラーを表示
最後に編集したユーザー inemaru on 2016年11月17日(木) 00:30 [ 編集 1 回目 ]

inemaru
記事: 108
登録日時: 7年前

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#6

投稿記事 by inemaru » 7年前

申し訳ありません。
質問斜め読みして、回答が的外れになってました。
(前の回答は、スポイラーテキストにしました。)

ポインタの付け替えで実現する場合は、以下の通りです。
↑ 間違いでした。このコードの動作は、コピーです。ご注意ください。

コード:

// 環境:VS2013
#include <cstdio>
#include <array>

std::array<int, 5> b = { 11, 12, 13, 14, 15 };

void setPointer(std::array<std::array<int, 5>, 2>& refA) {
	refA[0] = b;
}

void output(){
	printf("bのアドレス = %p\n", &b.front());
	printf("b=");
	for (const int& value : b) {
		printf("%d, ", value);
	}
	printf("\n");
}

int main(void)
{
	std::array<std::array<int, 5>, 2> a =
	{ {
		{ 1, 2, 3, 4, 5 },
		{ 6, 7, 8, 9, 10 }
		} };
	auto dispA = [&a]() -> void {
		printf("aのアドレス%p\n", &a.front());
		printf("a=");
		for (const auto& refI : a) {
			for (const int& refJ : refI) {
				printf("%d, ", refJ);
			}
		}
	};
	dispA();
	output();
	printf("\n配列aの先頭アドレスを配列bの先頭アドレスで書き換える\n\n");
	setPointer(a);
	dispA();
	return 0;
}
最後に編集したユーザー inemaru on 2016年11月17日(木) 01:30 [ 編集 1 回目 ]

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#7

投稿記事 by みけCAT » 7年前

ゆうさく さんが書きました:メイン関数で宣言した二次元配列の先頭ポインタを,他のソースファイルで宣言した一次元配列の中身で置き換える方法がわかりません.
配列の先頭ポインタ(配列から自動的に変換されるポインタ)を置き換えることも、ポインタを配列の中身で置き換えることもできない、またはやってもあまり意味がないと思いますが、
配列の要素であるポインタを別のポインタに書き換えることはできます。

ついでに、printf()に間違った型のデータを渡しているため未定義動作が発生する問題を修正しました。

コード:

/*Main.cpp*/
#include <stdio.h>
#include "Header.h"


int main(void){
	int adata[][5] = 
	{
		{ 1, 2, 3, 4, 5 },
		{ 6, 7, 8, 9, 10 }
	};
	int* a[] = {adata[0], adata[1]};
	

	// aのポインタと中身を表示
	printf("aのアドレス%p\n", (void*)a);
	
	printf("a=");
	for (int i = 0; i < 2; i++){
		for (int j = 0; j < 5; j++){
			printf("%d, ", a[i][j]);
		}
		printf("\n");
	}

	// bの中身を出力
	output();


	printf("\n配列aの先頭アドレスを配列bの先頭アドレスで書き換える\n\n");
	// 配列aのポインタを投げる
	setPointer(a);

	
	printf("a=");
	for (int i = 0; i < 2; i++){
		for (int j = 0; j < 5; j++){
			printf("%d, ", a[i][j]);
		}
		printf("\n");
	}


	return 0;
}

コード:

/*Sub.cpp*/

#include <stdio.h>

int *pointer;
int b[] = {11,12,13,14,15};


void setPointer(int* p[2]){
	p[0] = b;
}


void output(){
	printf("bのアドレス = %p\n", (void*)b);

	printf("b=");
	for (int i = 0; i < 5; i++){
		printf("%d, ", b[i]);
	}
	printf("\n");
}

コード:

/* Header.h */
#ifndef HEADER_H_GUARD_D4A8A44E_E43C_48CB_87F5_51AA536EE4B1
#define HEADER_H_GUARD_D4A8A44E_E43C_48CB_87F5_51AA536EE4B1

void setPointer(int* p[2]);
void output();

#endif
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#8

投稿記事 by みけCAT » 7年前

inemaru さんが書きました:ポインタの付け替えで実現する場合は、以下の通りです。
このコードでやっているのは、ポインタの付け替えではなくコピーではないですか?
コピーであると推測する根拠として、このNo: 6のコードのreturn 0;の直前に

コード:

    b[1] = 77;
    a[0][3] = 99;
    dispA();
    output();
を追加した時のWandboxでの出力

コード:

aのアドレス0x7ffc20d54220
a=1, 2, 3, 4, 5, 6, 7, 8, 9, 10, bのアドレス = 0x601820
b=11, 12, 13, 14, 15, 

配列aの先頭アドレスを配列bの先頭アドレスで書き換える

aのアドレス0x7ffc20d54220
a=11, 12, 13, 14, 15, 6, 7, 8, 9, 10, aのアドレス0x7ffc20d54220
a=11, 12, 13, 99, 15, 6, 7, 8, 9, 10, bのアドレス = 0x601820
b=11, 77, 13, 14, 15
となっており、a[0]への変更がbに反映されておらず、bへの変更がa[0]に反映されていません。
今回の検証ではGCCを使用しましたが、inemaruさんの指定するVS2013では正しく「ポインタの付け替え」が行われていますか?

【追記】
VC(2013かは不明)で検証しましたが、同様にa[0]とbは独立しており、コピーが行われていると考えられます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

inemaru
記事: 108
登録日時: 7年前

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#9

投稿記事 by inemaru » 7年前

みけCAT さんが書きました:
inemaru さんが書きました:ポインタの付け替えで実現する場合は、以下の通りです。
となっており、a[0]への変更がbに反映されておらず、bへの変更がa[0]に反映されていません。
今回の検証ではGCCを使用しましたが、inemaruさんの指定するVS2013では正しく「ポインタの付け替え」が行われていますか?

【追記】
VC(2013かは不明)で検証しましたが、同様にa[0]とbは独立しており、コピーが行われていると考えられます。
ご指摘ありがとうございます。完全に自分のミスでした。
VS2013で確認したところ、コピーが行われています。
付け替えは行われていません。

落ち着いて考えると、std::arrayの代入はコピー動作が規定です。

恥ずかしいミスを晒してしまいました。
申し訳ありません。以後、注意します。

akasann

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#10

投稿記事 by akasann » 7年前

いまいち理解してませんが、ポインタを使わずに、このような形で置き換えてみました。最初はポインタで試みたのですが・・上手くいかなかったので切り替えてみました。参考になるか分りませんが・・・はっときます。

コード:

#include<stdio.h>
#define N 5

int b[N]={11,12,13,14,15};

void setpointer(int a[2][5],int b[N]){
	for(int i=0;i<N;i++){
		a[0][i]=b[i];
	}
}

int main(void){
	int a[][5]={{1,2,3,4,5},{6,7,8,9,10}};
	
	setpointer(a,b);
	for(int i=0;i<2;i++){
		for(int j=0;j<N;j++)
			printf("%3d",a[i][j]);
		putchar('\n');
	}
}

あんどーなつ
記事: 171
登録日時: 7年前
連絡を取る:

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#11

投稿記事 by あんどーなつ » 7年前

ポインタを使ったバージョンです。

Header.h

コード:

/*Header.h*/

typedef int *INTPTR;
extern INTPTR pointer[];

void setPointer(INTPTR p);
void output();

extern int b[];
Main.cpp

コード:

/*Main.cpp*/
#include <stdio.h>
#include "Header.h"


int main(void){
    int a[][5] =
    {
        { 1, 2, 3, 4, 5 },
        { 6, 7, 8, 9, 10 }
    };

        for (int i = 0; i < 2; ++i)
                pointer[i] = &(a[i][0]);

    // pointerのアドレスと中身を表示
    printf("pointerのアドレス%x\n", pointer);

    printf("pointer=");
    for (int i = 0; i < 2; i++){
        for (int j = 0; j < 5; j++){
            printf("%d, ", pointer[i][j]);
        }
        printf("\n");
    }

    // bの中身を出力
    output();


    printf("\nポインタpointerの先頭アドレスを配列bの先頭アドレスで書き換える\n\n");
    // 配列bのポインタを投げる
    setPointer(&(b[0]));

    printf("pointer=");
    for (int i = 0; i < 2; i++){
        for (int j = 0; j < 5; j++){
            printf("%d, ", pointer[i][j]);
        }
        printf("\n");
    }


    return 0;
}
Sub.cpp

コード:

/*Sub.cpp*/

#include <stdio.h>
#include "Header.h"

int b[] = {11,12,13,14,15};

INTPTR pointer[2];

void setPointer(INTPTR p) {
                pointer[1] = p;
}

void output(){
    printf("bのアドレス = %x\n", b);

    printf("b=");
    for (int i = 0; i < 5; i++){
        printf("%d, ", b[i]);
    }
    printf("\n");
}

ゆうさく

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#12

投稿記事 by ゆうさく » 7年前

みけCAT さんが書きました:配列の先頭ポインタ(配列から自動的に変換されるポインタ)を置き換えることも、ポインタを配列の中身で置き換えることもできない、またはやってもあまり意味がないと思いますが
ゆうさく さんが書きました:メイン関数で宣言した二次元配列の先頭ポインタを,他のソースファイルで宣言した一次元配列の中身で置き換える方法がわかりません.
みけCAT様のコードで試したところ,僕の望んでいた動作を実現できました.ありがとうございます.

最初は,コピー先配列の先頭ポインタをコピ―元配列の先頭ポインタで書き換えれば,配列の要素を実質的に同じにできると思っていました.
そうすれば配列内の要素すべてのコピーを行わなくてもよくなって,配列がどれだけ長くなろうとアドレスをコピーするだけで済むので処理が軽くなるのかなーと・・・.

しかし,以下のような代入は"aがポインタ定数"なるものらしくできないそうなので,

コード:

int a[3], b[] = {1,2,3};
int main(void){
  a = b;
}
また,ポインタのポインタなるものを使って,配列aのアドレスが格納されているアドレスからなんとかならんものかと考えたのですが,結局なんともなりませんでした….

みけCAT様のコードのおかげで配列の要素,先頭ポインタのコピーのみで二つの配列の要素を同じにすることができました,本当にありがとうございます.

YuO
記事: 947
登録日時: 13年前
住所: 東京都世田谷区

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#13

投稿記事 by YuO » 7年前

根本的な所で,「配列はポインタでは無い」ことに注意すべきかと。
代入で
ゆうさく さんが書きました:しかし,以下のような代入は"aがポインタ定数"なるものらしくできないそうなので,
といったエラーが出たようですが,文法上,特定の場合を除いて配列型のオブジェクトは配列の先頭要素へのポインタという値になるため,このようなエラーが出たのだと思います。
値というのは,つまりは1とかと同じなので,Cにおいて代入はできません。
オフトピック
► スポイラーを表示

あんどーなつ
記事: 171
登録日時: 7年前
連絡を取る:

Re: 二次元配列のポインタを他のソースファイルで書き換えたい

#14

投稿記事 by あんどーなつ » 7年前

あっ、分かりました!Java/C#風に書きたかったのですよね。その場合はSTLを使います

Header.h

コード:

/* Header.h */

#include <vector>

extern std::vector<std::vector<int>> a;
extern std::vector<int> b;

void print(std::vector<std::vector<int>>);
Main.cpp

コード:

/* Main.cpp */

#include <vector>
#include <iostream>
#include <algorithm>
#include "Header.h"

using namespace std;

int main() {
	print(a);
	a[1] = b;
	print(a);
	return 0;
}
Sub.cpp

コード:

/* Sub.cpp */

#include <vector>
#include <iostream>
#include <algorithm>
#include "Header.h"

using namespace std;

vector<vector<int>> a
	= { vector<int>{1,2,3,4,5},
	    vector<int>{6,7,8,9,10} };

vector<int> b = {11,12,13,14,15};

void print(vector<vector<int>> v) {
	for (int i = 0; i < a.size(); ++i)
        for (int j = 0; j < a[i].size(); ++j)
            cout << a[i][j] << " ";
    cout << endl;
}

閉鎖

“C言語何でも質問掲示板” へ戻る