構造体の動的配列の記述を教えてください。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ワド
記事: 2
登録日時: 5ヶ月前

構造体の動的配列の記述を教えてください。

#1

投稿記事 by ワド » 5ヶ月前

C言語初心者です。
参考書に書いてあるコードを書いていたのですが、配列に不定定数を入れる部分でエラーが出ており、これの直し方がわかりません。mallocを使用して試しているのですが、上手く動きません。
また逆参照になってしまっている部分,バッファオーバーランしている部分、についても直し方がわからないので、教えてほしいです。
Visual Studioを使用しています。
下記、コードになります。お願いします。



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

typedef struct bin_node {
int value;
struct bin_node* less_equal;
struct bin_node* bigger;
}BIN_NODE;
void set(BIN_NODE* src, BIN_NODE* dest) {
if (src->value > dest->value) {
if (dest->bigger) {
set(src, dest->bigger);
}
else
{
dest->bigger = src;
}
}
else {
if (dest->less_equal) {
set(src, dest->less_equal);
}
else {
dest->less_equal = src;
}
}
}
int main(int argc, char* argv[])
{
BIN_NODE nums[argc]; //エラーの部分

/* //mallocを使用して試した部分
BIN_NODE* nums =0;
nums= (BIN_NODE * )malloc(sizeof(BIN_NODE)*argc);
*/

nums[0].value = 0; //逆参照になっている部分
nums[0].less_equal = nums[0].bigger = NULL;
for (int i = 0; i < argc; i++) {
nums.value = atoi(argv); //バッファオーバーランしている部分
nums.less_equal = nums.bigger = NULL;
set(&nums, &nums[0]);
}
BIN_NODE* min = &nums[0];
while (min->bigger) //逆参照になっている部分
{
min = min->less_equal;

}
BIN_NODE* max = &nums[0];
while (max -> bigger) //逆参照になっている部分
{
max = max->bigger;

}
printf("min = %i,max = %i\n", min->value, max->value);
free(nums);
}

/code

Meta3

Re: 構造体の動的配列の記述を教えてください。

#2

投稿記事 by Meta3 » 5ヶ月前

読みやすくして

コード:

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

typedef struct bin_node {
	int value;
	struct bin_node* less_equal;
	struct bin_node* bigger;
}BIN_NODE;
void set(BIN_NODE* src, BIN_NODE* dest) {
	if (src->value > dest->value) {
		if (dest->bigger) {
			set(src, dest->bigger);
		}
		else
		{
			dest->bigger = src;
		}
	}
	else {
		if (dest->less_equal) {
			set(src, dest->less_equal);
		}
		else {
			dest->less_equal = src;
		}
	}
}
int main(int argc, char* argv[])
{
	BIN_NODE nums[argc]; //エラーの部分

	/* //mallocを使用して試した部分
	BIN_NODE* nums =0;
	nums= (BIN_NODE * )malloc(sizeof(BIN_NODE)*argc);
	*/

	nums[0].value = 0; //逆参照になっている部分
	nums[0].less_equal = nums[0].bigger = NULL;
	for (int i = 0; i < argc; i++) {
		nums.value = atoi(argv); //バッファオーバーランしている部分
		nums.less_equal = nums.bigger = NULL;
		set(&nums, &nums[0]);
	}
	BIN_NODE* min = &nums[0];
	while (min->bigger) //逆参照になっている部分
	{
		min = min->less_equal;

	}
	BIN_NODE* max = &nums[0];
	while (max->bigger) //逆参照になっている部分
	{
		max = max->bigger;

	}
	printf("min = %i,max = %i\n", min->value, max->value);
	free(nums);
}


Meta3

Re: 構造体の動的配列の記述を教えてください。

#3

投稿記事 by Meta3 » 5ヶ月前

エラー

コード:

c:\b>cl c1.c
Microsoft(R) C/C++ Optimizing Compiler Version 19.26.28806 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

c1.c
c1.c(30): error C2057: 定数式が必要です。
c1.c(30): error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c1.c(30): error C2133: 'nums': サイズが不明です。
c1.c(40): error C2231: '.value': 左のオペランドが 'struct' へのポインターです。'->' を使用してください。
c1.c(40): warning C4047: '関数': 間接参照のレベルが 'const char *' と 'char **' で異なっています。
c1.c(40): warning C4024: 'atoi': の型が 1 の仮引数および実引数と異なります。
c1.c(41): error C2231: '.less_equal': 左のオペランドが 'struct' へのポインターです。'->' を使用してください。
c1.c(41): error C2231: '.bigger': 左のオペランドが 'struct' へのポインターです。'->' を使用してください。
c1.c(42): warning C4047: '関数': 間接参照のレベルが 'BIN_NODE *' と 'BIN_NODE (*)[0]' で異なっています。
c1.c(42): warning C4024: 'set': の型が 1 の仮引数および実引数と異なります

Meta3

Re: 構造体の動的配列の記述を教えてください。

#4

投稿記事 by Meta3 » 5ヶ月前

argc は実行時の引数の個数ですから

コード:

#include <stdio.h>

int main(int argc, char *argv[]){
  int i;
  
  printf("文字列の個数 %d\n",argc);
  for(i=0;i<argc;i++)
    printf("%d 番目の文字列 %s\n",i,argv[i]);
  return 0;
}

Meta3

Re: 構造体の動的配列の記述を教えてください。

#5

投稿記事 by Meta3 » 5ヶ月前

コード:

c:\b>c1.exe 123 abc
文字列の個数 3
0 番目の文字列 c1.exe
1 番目の文字列 123
2 番目の文字列 abc

Meta3

Re: 構造体の動的配列の記述を教えてください。

#6

投稿記事 by Meta3 » 5ヶ月前

argc は定数式ではないので配列は宣言出来ません

参考書に書いてあるコードを書いていたのですが、
とありますが よく確認してみましょう



Meta3

Re: 構造体の動的配列の記述を教えてください。

#9

投稿記事 by Meta3 » 5ヶ月前

独習C 新版 という本の312ページに リスト11.9  ch11-08.c
として 同じプログラムがあるようです

2分木でコマンドライン引数を昇順にならべかえるそうです

例として
> a.exe 1 5 80 -3 3 5 32 97
min=-3,max=97

となっているようです
unix系 なので テストできませんが

使っている OS コンパイラは何ですか

Meta3

Re: 構造体の動的配列の記述を教えてください。

#10

投稿記事 by Meta3 » 5ヶ月前

VisualStudio ですからWindowsですね
う~ん 何か方法があるのかな

Meta3

Re: 構造体の動的配列の記述を教えてください。

#11

投稿記事 by Meta3 » 5ヶ月前

VisualStudio ですからWindowsですね
う~ん 何か方法があるのかな

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

Re: 構造体の動的配列の記述を教えてください。

#12

投稿記事 by みけCAT » 5ヶ月前

ソースコードを提示する際は、BBCodeが有効な(無効にしない)状態で、
BBCodeのcodeタグの開始タグと終了タグの組(開始タグが先)で囲んでいただけると、
見やすくてありがたいです。
[]で囲まれていないcodeや/codeは、codeタグではありません。
ワド さんが書きました:
5ヶ月前
参考書に書いてあるコードを書いていたのですが、配列に不定定数を入れる部分でエラーが出ており、これの直し方がわかりません。
これは可変長配列(Variable-Length Array)といい、C99では必ず認められ、C11ではオプションの仕様です。
したがって、対応するコンパイラ(gccなど)をC99モード(gccなら-std=c99)で用いるといいでしょう。
ワド さんが書きました:
5ヶ月前
mallocを使用して試しているのですが、上手く動きません。
i=0のときもset(&nums[​i], &nums[0]);をしているため、
自分への辺ができてしまい、無限ループになってしまいます。
forループをi=0ではなくi=1から始めるようにするといいでしょう。
このことにより、通常argv[0]として与えられる実行ファイルのファイル名を
数値として処理しようとすることも回避できます。
さらに、mallocが成功したかを確かめるため、戻り値がNULLでないかをチェックし、
もしNULLであったらその後の処理を中止するような処理を入れるといいでしょう。
ワド さんが書きました:
5ヶ月前
また逆参照になってしまっている部分,バッファオーバーランしている部分、についても直し方がわからないので、教えてほしいです。
「逆参照」をググったところ、間接参照と同じような意味であり、悪いことではなさそうです。

「逆参照になっている部分」のうち、

コード:

	while (min->bigger) //逆参照になっている部分
	{
		min = min->less_equal;

	}
については、条件をmin->biggerではなくmin->less_equalにするといいでしょう。
他の2箇所については、特に直さなくてよさそうです。

また、「バッファオーバーランしている部分」についても、
特に範囲外アクセスになりそうな処理は見られず、直さなくてよさそうです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: 構造体の動的配列の記述を教えてください。

#13

投稿記事 by みけCAT » 5ヶ月前

Meta3 さんが書きました:
5ヶ月前
読みやすくして
掲示板の不親切設計によって[​/i]が無いのにも関わらず[​i]が斜体を表すタグとして解釈され、消えています。
その消えたままのコードを使用しているため、不正なコードになっています。
codeタグを使わずに貼り付けられたコードは、表示された本文から直接コピペするのではなく、
引用ボタンを押して引用投稿用のフォームからコピペするといいでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: 構造体の動的配列の記述を教えてください。

#14

投稿記事 by みけCAT » 5ヶ月前

nums[0].valueに入れている0についても最大値や最小値を求める対象としているため、
全て正の数を入力した時にはmin = 0となってしまいます。
また、全て負の数を入力したときにはmax = 0となってしまいます。
これを回避するには、例えばnums[0].valueにはINT_MIN (limits.hで定義) を入れておき、
&nums[0]ではなくnums[0].biggerから最大値や最小値の探索を始める、という方法が考えられます。
ただし、この場合引数を与えずに実行した時にNULLをデリファレンスしてエラーになる可能性があるので、
このケースへは別途対処するべきでしょう。

また、malloc()系の関数で確保したポインタでもNULLでないポインタをfree()に渡してはいけません。
すなわち、

コード:

	BIN_NODE nums[argc]; //エラーの部分
に対して

コード:

	free(nums);
を実行してはいけません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
あたっしゅ
記事: 458
登録日時: 10年前
住所: 東京23区
連絡を取る:

Re: 構造体の動的配列の記述を教えてください。

#15

投稿記事 by あたっしゅ » 5ヶ月前

コード:

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


typedef struct bin_node {
    int value;
    struct bin_node* less_equal;
    struct bin_node* bigger;
}BIN_NODE;


void set(BIN_NODE* src, BIN_NODE* dest) {
    if (src->value > dest->value) {
        if (dest->bigger) {
            set(src, dest->bigger);
        }
        else
        {
            dest->bigger = src;
        }
    }
    else {
        if (dest->less_equal) {
            set(src, dest->less_equal);
        }
        else {
            dest->less_equal = src;
        }
    }
}


int main(int argc, char* argv[])
{
    //BIN_NODE nums[argc]; //エラーの部分

   //mallocを使用して試した部分
    BIN_NODE* nums= (BIN_NODE *)malloc(sizeof(BIN_NODE)*argc);

    if( argc>2 ) {
        printf( "argv[ %d ]%s\n", 1, argv[ 1 ] );
        nums[ 0 ].value = atoi( argv[ 1 ] ); //バッファオーバーランしている部分
        nums[ 0 ].less_equal = nums[ 0 ].bigger = nullptr;

        for (int i = 2; i < argc; i++) {
            printf( "argv[ %d ]%s\n", i, argv[ i ] );
            nums[ i-1 ].value = atoi( argv[ i ] ); //バッファオーバーランしている部分
            nums[ i-1 ].less_equal = nums[ i-1 ].bigger = nullptr;
            set(&nums[ i-1 ], &nums[0]);
        }

        BIN_NODE* min = &nums[0];
        while (min->less_equal != nullptr ) //逆参照になっている部分
        {
            min = min->less_equal;

        }

        BIN_NODE* max = &nums[0];
        while (max -> bigger != nullptr ) //逆参照になっている部分
        {
            max = max->bigger;

        }

        printf("min = %i,max = %i\n", min->value, max->value);
    }
    free(nums);

    return 0;
}
https://www.onlinegdb.com/ の C++ 17 で確認。


https://qiita.com/hikarabitagobou/items ... 5783a2463c
argc, argv とは? - Qiita(ja)

https://qiita.com/keitean/items/1a79c96adcf3fc02b1e5"
C言語 main(int argc, char const *argv[]) について - Qiita(ja)

https://ja.wikipedia.org/wiki/Null
Null - ジャパリ図書館(ja)


// end.
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.rosx.net/vtuber/index.html
レスがついていないものを優先して、レスすみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたっしゅ、[MrAtassyu]
http://ameblo.jp/mratassyu/
Pixiv: 666303
手提鞄屋魚有店(てさげかばんやうおありてん)

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

Re: 構造体の動的配列の記述を教えてください。

#16

投稿記事 by みけCAT » 5ヶ月前

ワド さんが書きました:
5ヶ月前
C言語初心者です。
あたっしゅ さんが書きました:
5ヶ月前
C++ 17 で確認。
うーん…まあ、C言語初心者だからといってC言語を使っているとは限らない、
むしろ初心者だからC言語を使うのを避けるという可能性もあるからなあ…
ただ、C++ならmalloc/freeではなくnew/deleteやstd::vectorを使うべきではないかなあ…?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Meta3

Re: 構造体の動的配列の記述を教えてください。

#17

投稿記事 by Meta3 » 5ヶ月前

#15 のコード VisualStudio2019 で c1.cpp として動きました

コード:

c:\b\p>cl /EHsc c1.cpp
Microsoft(R) C/C++ Optimizing Compiler Version 19.26.28806 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

c1.cpp
Microsoft (R) Incremental Linker Version 14.26.28806.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:c1.exe
c1.obj

c:\b\p>c1.exe

c:\b\p>c1.exe 1 9 6 3
argv[ 1 ]1
argv[ 2 ]9
argv[ 3 ]6
argv[ 4 ]3
min = 1,max = 9

c:\b\p>
c1.c ではエラー
c++としてのc

Meta3

Re: 構造体の動的配列の記述を教えてください。

#18

投稿記事 by Meta3 » 5ヶ月前

この本はclang を解説しているようです

ワド
記事: 2
登録日時: 5ヶ月前

Re: 構造体の動的配列の記述を教えてください。

#19

投稿記事 by ワド » 5ヶ月前

投稿したものです。
確認不足でclangではなくvisual studioの標準のものでコンパイルしていたため、clangに直した所実行することができました。
様々な意見からC言語そのものの勉強が圧倒的に足りていないということを知れたので、今以上に勉強に励みたいと思います。

Meta3

Re: 構造体の動的配列の記述を教えてください。

#20

投稿記事 by Meta3 » 5ヶ月前

#13 で教えていただいた
「@「「掲示板の不親切設計によって[​/i]が無いのにも関わらず[​i]が斜体を表すタグとして解釈され、消えています。
その消えたままのコードを使用しているため、不正なコードになっています。」を修正

コード:

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

typedef struct bin_node {
	int value;
	struct bin_node* less_equal;
	struct bin_node* bigger;
}BIN_NODE;
void set(BIN_NODE* src, BIN_NODE* dest) {
	if (src->value > dest->value) {
		if (dest->bigger) {
			set(src, dest->bigger);
		}
		else
		{
			dest->bigger = src;
		}
	}
	else {
		if (dest->less_equal) {
			set(src, dest->less_equal);
		}
		else {
			dest->less_equal = src;
		}
	}
}
int main(int argc, char* argv[])
{
	BIN_NODE nums[argc]; //エラーの部分

	/* //mallocを使用して試した部分
	BIN_NODE* nums =0;
	nums= (BIN_NODE * )malloc(sizeof(BIN_NODE)*argc);
	*/

	nums[0].value = 0; //逆参照になっている部分
	nums[0].less_equal = nums[0].bigger = NULL;
	for (int i = 0; i < argc; i++) {
		nums[i].value = atoi(argv[i]); //バッファオーバーランしている部分
		nums[i].less_equal = nums[i].bigger = NULL;
		set(&nums[i], &nums[0]);
	}
	BIN_NODE* min = &nums[0];
	while (min->bigger) //逆参照になっている部分
	{
		min = min->less_equal;

	}
	BIN_NODE* max = &nums[0];
	while (max->bigger) //逆参照になっている部分
	{
		max = max->bigger;

	}
	printf("min = %i,max = %i\n", min->value, max->value);
	free(nums);
	
}


Meta3

Re: 構造体の動的配列の記述を教えてください。

#21

投稿記事 by Meta3 » 5ヶ月前

VisualStudio2019 のclang 10.0 コンパイル

コード:

c:\b>clang-cl --version
clang version 10.0.0
Target: i686-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\bin

c:\b>clang-cl /w4 c1.c

c:\b>

Meta3

Re: 構造体の動的配列の記述を教えてください。

#22

投稿記事 by Meta3 » 5ヶ月前

間違いがあるようです  正しくは

コード:

#include <stdio.h>
#include <stdlib.h>
typedef struct bin_node {   // 定義内で自構造体を利用するのでタグが必要
    int value;
    struct bin_node *less_equal;  // 構造体指定子が完了していないので「struct タグ」で参照
    struct bin_node *bigger; // 構造体指定子が完了していないので「struct タグ」で参照
} BIN_NODE;                 // 型名
// 設定先のノードよりも値が大きければright、小さいか等しければleftに設定する関数
// パラメータの構造体自体を書き換えるので、ポインターで受け取る必要がある
void set(BIN_NODE *src, BIN_NODE *dest) {
    if (src->value > dest->value) {
        if (dest->bigger) { // すでに他の構造体をポイントしていればその構造体に設定
            set(src, dest->bigger); 
        } else {
            dest->bigger = src;
        }
    } else {
        if (dest->less_equal) { // すでに他の構造体をポイントしていればその構造体に設定
            set(src, dest->less_equal);
        } else {
            dest->less_equal = src;
        }
    }
}
int main(int argc, char *argv[])
{
    BIN_NODE nums[argc]; // 要素0を起点とする
    nums[0].value = 0;
    nums[0].less_equal = nums[0].bigger = NULL;
    for (int i = 1; i < argc; i++) {
        nums[i].value = atoi(argv[i]);
        nums[i].less_equal = nums[i].bigger = NULL;
        // 起点の要素0から小さい(less_equal)、大きい(bigger)に振り分ける
        set(&nums[i], &nums[0]);
    }
    BIN_NODE *min = &nums[0];
    // 起点からless_equalが指す構造体を終端(less_equalがNULL)までたどると最小値
    while (min->less_equal) {
        min = min->less_equal;
    }
    BIN_NODE *max = &nums[0];
    // 起点からbiggerが指す構造体を終端(biggerがNULL)までたどると最大値
    while (max->bigger) {
        max = max->bigger;
    }
    printf("min=%i, max=%i\n", min->value, max->value);
}


Meta3

Re: 構造体の動的配列の記述を教えてください。

#23

投稿記事 by Meta3 » 5ヶ月前

コード:

c:\b>clang-cl c1.c

c:\b>c1,exe 3 -3 80 97
min=-3, max=97

c:\b>c1.exe 123 456 789 2
min=0, max=789

c:\b>

Meta3

Re: 構造体の動的配列の記述を教えてください。

#24

投稿記事 by Meta3 » 5ヶ月前

#14 の 0 対策 はしてないようです

Meta3

Re: 構造体の動的配列の記述を教えてください。

#25

投稿記事 by Meta3 » 5ヶ月前

「訂正」

コード:

c:\b>c1.exe 3 -3 80 97
min=-3, max=97

c:\b>

Meta3

Re: 構造体の動的配列の記述を教えてください。

#26

投稿記事 by Meta3 » 5ヶ月前

コード:

for (int i = 0; i < argc; i++) {
		nums.value = atoi(argv); //バッファオーバーランしている部分
がただしくは

コード:

 for (int i = 1; i < argc; i++) {
        nums[i].value = atoi(argv[i]);
ですね

返信

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