プロが教えるわが家の防犯対策術!

構造体メンバーのカンマ区切り出力をしたいと思っています。

たとえば
struct XXX {
char name[20];
char address[40];
char tel[12];
... 100メンバーくらいある
}
のような構造体があったとします。
printf("%s,%s,%s\n", s_ptr->name, s_ptr->address, s_ptr->tel);
などのようにメンバー名(変数名)を参照せずに、構造体のメンバーへのポインタを順次取得しループして出力するなどして、実現することは可能でしょうか?

このQ&Aに関連する最新のQ&A

A 回答 (6件)

こんにちわ。



構造体のメンバー名を使用せずにポインタでアクセスする事は可能ですが、
移植性やメンテナンス効率が悪くなるので、通常はあまりやりません。
例えば例にある構造体で、
st *struct XXX;
となっていた場合、
strcpy(tel, ((char *)(st) + 60));
とすれば、tel メンバーにアクセスできます。

※ 構造体内に様々なデータ型を含む場合は、領域が獲得される領域が
  整列されるため、構造体内のオフセットの計算に注意する必要が
  あります。

以前使っていたマクロですが、
#defineSTOFFSET(st ,member)((long)(&((st *)0)->member))
と宣言して、

printf("Offset (tel) = %d\n", STOFFSET(struct XXX, tel));
とすれば、メンバー内のオフセットを計算できます。
参考にして下さいね。
    • good
    • 0
この回答へのお礼

ご回答詳細にありがとうございます。

いただいた情報を元にさらに調べたところ、taka_tetsu様のご回答の“からくり”の部分に相当することなのですね。
いただいた情報から更に検索すると下記の情報も得られました。
どうもありがとうございました。
--<C FAQ>--
2.14:
構造体内のフィールドのバイトオフセットを知る方法は。
A:
ANSI Cは、offsetofマクロを用意しているので、用意されている場合 は使うこと。<stddef.h>を参照。もし手に入れることができなければ、 実装の一つは以下のようになる。



#define offsetof(type, mem) ((size_t) \
((char *)&((type *)0)->mem - (char *)(type *)0))


この実装も100%の移植性を持つわけではない。コンパイラの中には、 はねつけるものがあるかもしれないが、それはそれで文法的に正しい。

次の質問2.15への解答を、使い方の参考にすること。

References:
ANSI Sec. 4.1.5; ISO Sec. 7.1.6; Rationale Sec. 3.5.4.2; H&S Sec. 11.1 pp. 292-3.


--------------------------------------------------------------------------------
2.15:
どうやれば構造体のフィールドを、実行時に名前でアクセスできるか。

A:
まずoffsetof()マクロを使って名前とオフセットの対応表を用意する。 構造体aのフィールドbのオフセットは、


offsetb = offsetof(struct a, b)


で与えられる。もし以下の式でstructpが、構造体の実体へのポイン ターで、bが上で計算したオフセットを持つintのフィールドとすると、 bの値は間接的に


*(int *)((char *)structp + offsetb) = value;


として得られる。
--

お礼日時:2002/11/13 10:48

構造体のメンバーをポインタにできるのなら比較的楽ですね。


以下のように union にしてもよいですし、無理矢理 cast しちゃってもよいですし。
union uXXX {
 struct XXX {
  char *name;
  char *address;
  char *tel;
   :
 }
 char* aaa[100];
};
    • good
    • 0
この回答へのお礼

どうもありがとうございます!

残念ながら、構造体は私が設計したものではないので、いじれないのです。 (;_;

これ、おもしろいですね!
参考にさせていただきます。ありがとうございます。

お礼日時:2002/11/29 22:50

なんかそもそもそのような構造体を作ること自体の設計に問題がありそうですけど。



もし、メンバーが全部char ならば(つまり同一という意味)、

struct XXX {
char *member[100];
} s;

enum {_name, _address, _tel, ...} index;

として、

s.member[_name] = "namae";
....
そして、まとめて取り扱うときには、
index = 0;
s.member[index]

のようにするのが普通と思います。

いかがでしょう?
    • good
    • 0
この回答へのお礼

どうもありがとうございます!

残念ながら、構造体は私が設計したものではないので、いじれないのです。
どうもありがとうございます。

教えていただいた方法というのもありですね。
どうもありがとうございます。

お礼日時:2002/11/29 22:47

ああ、ごめんなさい。


よく読んでませんでした。

メンバをポインタ経由で参照するということですよね?

可能です。が、やはりお薦めできません。

他の方がおっしゃっているように移植性の問題やらが大変なので一つ一つのメンバにアクセスした方が結果的にラクです。

この回答への補足

いえいえ、とんでもないです。ありがとうございました。

補足日時:2002/11/29 22:20
    • good
    • 0

いっそのこと構造体を typedef で型にしてからその配列にアクセスするという方法はどうです?



*************************************************

#include <stdio.h>

typedef struct {
int hoge;
int piyo;
char name[64];
} DATA;

int main(void){
int i;
DATA data[] = { { 10, 20, "hoge" },
{ 20, 30, "piyo" },
{ 30, 40, "name" } };

for( i = 0; i < 3; i++ ){
printf( "%d,%d,%s\n", data[i].hoge, data[i].piyo, data[i].name );
}

return 0;
}

*************************************************

これなら動的に確保することも容易ですし。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

恐れ入りますが、構造体のインスタンス?(コピー)が多いのではなく、あくまで「メンバー」が多いので、メンバー名を使用したくないのです。

よろしくお願いします。

お礼日時:2002/11/13 10:50

offsetofで構造体の先頭からのバイト数取得し、あらかじめ配列に格納しておいて、それをループでまわすというのは?



もちろん、intなんかが混じってたら別の方法を考えないとダメでしょうけど。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

こんな演算子があったのですね?と思ったら、ちょっと調べてみたところマクロなのですね。知りませんでした。

活用して工夫してみます。ありがとうございます。

お礼日時:2002/11/13 10:44

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QC言語で構造体のメンバを簡単に出力する方法ありますか?

いつもお世話になっています。

C言語の質問です。
単体テストログを取るために、
“関数Aをコールする前後で、関数Aに引数として渡す構造体のメンバをすべて”printf(もしくはfprintf)で出力して比較確認しなければならないのですが、

構造体のメンバが250とか、150とかあり、メンバ名もxxx_01,xxx_02などのようにエクセルなどで簡単に加工して作れるものではないので、いちいちメンバ名を指定しなければならないのでとても大変です。

オブジェクト指向言語なら、for each文とかでオブジェクトのメンバを簡単に取り出せるのでしょうが(間違っているかもしれません・・・)、C言語で構造体のメンバを、for文などのループを使って簡単に出力できる方法はないでしょうか?

メンバの型は、一定ではなく、char、int、double、別の構造体のポインタ型(これは出力しなくて良い)と混在しています。メンバが全て同一の型ならポインタで構造体の先頭アドレスからsizeof(メンバの型)の分インクリメントしていけば出力できそうな気もしますが、メモリ上に連続して確保されるのかも私にはわからないので困っています。

enumで列挙して・・・というのも調べてみましたが、応用は出来ないようでした。

どなたか、地道にメンバ名を書いて出力する以外の方法をご存知の方、いらっしゃいましたらお知恵をお貸しください。
よろしくお願いいたします。
※説明不足の点がありましたら補足いたします。

いつもお世話になっています。

C言語の質問です。
単体テストログを取るために、
“関数Aをコールする前後で、関数Aに引数として渡す構造体のメンバをすべて”printf(もしくはfprintf)で出力して比較確認しなければならないのですが、

構造体のメンバが250とか、150とかあり、メンバ名もxxx_01,xxx_02などのようにエクセルなどで簡単に加工して作れるものではないので、いちいちメンバ名を指定しなければならないのでとても大変です。

オブジェクト指向言語なら、for each文とかでオブジェクトのメンバを...続きを読む

Aベストアンサー

コードを書かないという方向性の提案を一つ。
デバッガに構造体の内容を出力させるというのはどうでしょうか。

struct {
int a;
char *b;
double c;
}
という型を持つ変数xがあったとして、gdbでは下記のような出力が得られます。
(gdb) print x
$1 = {
a = 123,
b = 0x2fd0 "ABC",
c = -9876.5
}

Q構造体の変数の値を、動的に取得する方法を教えてください

C言語で、構造体の変数の値を取得したいのですが、その際、
他の変数に格納してある文字列を元に動的に行いたいのですが、可能でしょうか?

イメージとしては、
struct Entry{
char name[20];
char address[80];
char email[40];
};
struct Entry data;
strcpy(data.name, "Taro");
strcpy(data.address, "Tokyo");
strcpy(data.email, "taro@taro");

char var_name[20];
strcpy(var_name, "email");

printf("%s", data.var_name);
↑この行の構造体の変数へのアクセス方法が間違っているのはわかっていますが、このような時に「taro@taro」と出力させたいのです。

var_nameの値を「name, address, email」に換える事により「Taro, Tokyo, taro@taro」と出力を切り換えたいと思っています。

普段は他の言語をよく使用しており、そちらではこの手法を時々使っていたのですが、C言語でも出来ないものかと思っております。

よろしくお願いします。

C言語で、構造体の変数の値を取得したいのですが、その際、
他の変数に格納してある文字列を元に動的に行いたいのですが、可能でしょうか?

イメージとしては、
struct Entry{
char name[20];
char address[80];
char email[40];
};
struct Entry data;
strcpy(data.name, "Taro");
strcpy(data.address, "Tokyo");
strcpy(data.email, "taro@taro");

char var_name[20];
strcpy(var_name, "email");

printf("%s", data.var_name);
↑この行の構造体の変数へのアク...続きを読む

Aベストアンサー

既に多数出ていますが、
そもそもC言語では関数名や手続きなどはプロジェクト内、
またはファイル内において一意で認識される名前である必要が
あるため「同名で」「別の手続き」というのは、
そもそものC言語での考え方では厳しいといえると思います。

それっぽくC言語での例だと
こんな感じになると思います。
(インデントは全角スペースなのでコンパイルには注意)
#include <stdio.h>
#include <string.h>

#define MAXBUFFERLEN (80)

/* varメンバの擬似連想配列に対する列挙指定子 */
enum{
 name = 0,
 email,
 address,
 
 /* ここに指定子を追加することで、 *
  * 構造体メンバの配列も大きくなっていく */
 age, //例えば年齢を追加。(ただし扱いは文字列)

 MAXVARELEMENT,
};

/* 構造体にこだわるなら */
struct Entry{
 char var[MAXVARELEMENT][MAXBUFFERLEN];
};

int main( void )
{
 struct Entry data;
 strcpy(data.var[name], "Taro");
 strcpy(data.var[address], "Tokyo");
 strcpy(data.var[email], "taro@taro");
 strcpy(data.var[age], "20");

 printf( "%s\n", data.var[name] );
 printf( "%s\n", data.var[address] );
 printf( "%s\n", data.var[email] );
 printf( "%s\n", data.var[age] );
 return 0;
}

既に多数出ていますが、
そもそもC言語では関数名や手続きなどはプロジェクト内、
またはファイル内において一意で認識される名前である必要が
あるため「同名で」「別の手続き」というのは、
そもそものC言語での考え方では厳しいといえると思います。

それっぽくC言語での例だと
こんな感じになると思います。
(インデントは全角スペースなのでコンパイルには注意)
#include <stdio.h>
#include <string.h>

#define MAXBUFFERLEN (80)

/* varメンバの擬似連想配列に対する列挙指定子 */
enum{...続きを読む

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);

Qカンマ区切りのデータを配列に読み込みたい

趣味でゲームを製作しているのですが、その中で、
マップデータのテキストファイルを二次元配列に読み込むようにしています。
データファイルは、カンマ区切りで、例えば、
1,2,3,4,5
5,4,3,2,1
1,2,3,4,5
というようになっています。

fp=fopen(path,"r");
for(j=0; j<3; j++)
{
for(i=0; i<5; i++)
{
char c;
do{c=(getc(fp));}
while(c==','||c=='\n'||c=='\r');
map[j][i] = c-'0';
}
}

配列の各要素に読み込む中身が、0~9など1文字に限られている場合、このgetc()を使う方法で問題ないのですが、0~255など、文字数がまちまちになると、1文字を取り出すgetc()ではできなくなってしまいます。

これがどうすれば可能になるのか、情けないのですがちょっと思いつかないので、アドバイスを頂ければ幸いです。

Aベストアンサー

少し手を入れたらできそうですね。


{
char c;
do{c=(getc(fp));}
while(c==','||c=='\n'||c=='\r');
//-----------追加-----ここから
// int calc; の宣言要
calc = 0;
do { calc = (c - '0') + (calc*10);}
while(isdigit(c=getc(fp)));
//-----------追加-----ここまで
map[j][i] = calc;
}

Qファイルから読み込んだデータを構造体に格納できますか?

1レコード19バイトのファイルを
読み込む処理を行っています。

地区名10バイト
県名8バイト
改行1バイト

このデータをdouken(構造体)に格納したいのですが
>while (fgets(dou,19,fp) != NULL){
で、エラーになってしまいます。

どのようにしたら
ファイルから読み込んだデータを
構造体に格納できますか?


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

struct douken {
char tiku[10];
char ken[8];
}

main(void){

FILE *fp;
struct douken dou[100];
int i;

fp = fopen("ex3.fil","rb");

if ( fp == 0 ){
printf("can't open\n");
exit(1);
}

while (fgets(dou,19,fp) != NULL){



1レコード19バイトのファイルを
読み込む処理を行っています。

地区名10バイト
県名8バイト
改行1バイト

このデータをdouken(構造体)に格納したいのですが
>while (fgets(dou,19,fp) != NULL){
で、エラーになってしまいます。

どのようにしたら
ファイルから読み込んだデータを
構造体に格納できますか?


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

struct douken {
char tiku[10];
char ken[8];
}

main(void){

FILE *fp;
struct douken dou[100];
int i;

...続きを読む

Aベストアンサー

>>while (fgets(buffer,20,fp) != NULL){
>と、するということですか?
>その場合、
>ここのサイズは必ず4の倍数になるということですよね?
構造体を直接扱うと、アーキテクスチャやコンパイラ依存してしまいます。
32bit機なら4byteですし、16bit機なら2byte。64bit機なら8byteです。
また、コンパイラの設定によってもどのように確保されるかまったく分からないのです。
一度バッファに蓄えてからmemcpyでコピーする方が安全ですし、可搬性があります。
C言語では\0を文字列の終端文字として使用しているので、10文字格納したいなら11byte確保する必要もあります。
簡単に修正してみました。

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

typedef struct douken_ {
char tiku[11];
char ken[9];
} douken;

int main(void){
FILE *fp;
douken dou [100];
char buff [18 /* douken */ + 1 /* LF(\n) */ + 1 /* \0 */];
int i;
i = 0;

fp = fopen("ex3.fil","rb");

if ( fp == 0 ){
printf("can't open\n");
exit(1);
}

// douを\0で埋める
memset (dou , '\0' , sizeof dou);

// 一度バッファに格納
while (fgets(buff,sizeof buff,fp) != NULL){
// memcpy関数でコピー
memcpy(&dou[i],buff,10);
memcpy(&dou[i],buff+10,8);

// 構造体配列より大きなファイルを開いたときの配慮
if (i == 99) break;
i++;
}

return 0;
}

>>while (fgets(buffer,20,fp) != NULL){
>と、するということですか?
>その場合、
>ここのサイズは必ず4の倍数になるということですよね?
構造体を直接扱うと、アーキテクスチャやコンパイラ依存してしまいます。
32bit機なら4byteですし、16bit機なら2byte。64bit機なら8byteです。
また、コンパイラの設定によってもどのように確保されるかまったく分からないのです。
一度バッファに蓄えてからmemcpyでコピーする方が安全ですし、可搬性があります。
C言語では\0を文字列の終端文字として使用して...続きを読む

Q構造体のファイル出力

以下のような構造体を、テキストファイルに保存するにはどうしたらよいでしょうか?
構造体には、4つのデータがある場合、以下のようにします。

[構造体]
typedef struct comp_bango {
char bango[3];
} COMP;

出力テキスト
100 200 300 400

Aベストアンサー

★構造体『bango[3]』に数字が3つ入っていると仮定して回答します。
・つまり、
 bango[0] = '1';
 bango[1] = '0';
 bango[2] = '0';
 で『100』という数値が入っているとする。
・上記の場合ならば、『fputc』関数で『bango[0]』~『bango[2]』の3つを
 出力すれば良いと思います。
・下のサンプルを参照して下さい。

サンプル:
COMP CompData[ 4 ] = {
 { '1', '0', '0' },
 { '2', '0', '0' },
 { '3', '0', '0' },
 { '4', '0', '0' },
}; int n, i; FILE *fp;

if ( (fp = fopen("filename.txt","w")) != NULL ){
 for ( n = 0 ; n < 4 ; n++ ){ ←4つのデータだから
  for ( i = 0 ; i < 3 ; i++ ){ ←『bango[0]』~『bango[2]』の3つ
   fputc( CompData[n].bango[i], fp );
  }
  fputc( 0x20, fp ); ←間に空白文字を入れて出力
 }
 fclose( fp );
}

最後に:
・構造体メンバ『bango』には数字文字が3つ入るのですよね。
・1つのデータに文字列の終端を示す'\0'は納めたいのならば、構造体のメンバに
 『bango[4]』にすべきだと思いますが…。
・以上。おわり。

★構造体『bango[3]』に数字が3つ入っていると仮定して回答します。
・つまり、
 bango[0] = '1';
 bango[1] = '0';
 bango[2] = '0';
 で『100』という数値が入っているとする。
・上記の場合ならば、『fputc』関数で『bango[0]』~『bango[2]』の3つを
 出力すれば良いと思います。
・下のサンプルを参照して下さい。

サンプル:
COMP CompData[ 4 ] = {
 { '1', '0', '0' },
 { '2', '0', '0' },
 { '3', '0', '0' },
 { '4', '0', '0' },
}; int n, i; FILE *fp;

if ( (fp = fop...続きを読む

Qc#で(",")区切りのcsvファイルから読み込みを行うには?

駆け出しの初心者です。
以前c言語を少々勉強していてcsvファイルの読み込み、書き出しを練習していたのですが、最近c#を使うようになり、その便利さに圧倒されております。

今回c#で読み込みたいcsvファイルは以下のようになっております
"abc","123","あいうえお"

ただのカンマ区切りであれば読み込みは簡単ですが、
上記のようにダブルクオーテーションでそれぞれの文字列が囲まれている場合に文字列だけを読み込み、配列に代入していくのに何かスムーズな方法はありませんでしょうか?


ちなみに現在単純にカンマ区切りのcsvファイルを読み込むコードを
書いた所ですので、載せておきます
これをいじってスムーズにいければうれしいのですが、いかがでしょうか?

private void LoadData()
{
string path = "Data.csv";
string delimStr = ",";//区切り文字
char[] delimiter = delimStr.ToCharArray();
string[] strData;//分解後の文字用変数
string strLine;//1行分のデータ
Boolean fileExists = System.IO.File.Exists(path);
if (fileExists)
{
System.IO.StreamReader sr = new System.IO.StreamReader(
path,
System.Text.Encoding.Default);
while (sr.Peek() >= 0)
{
strLine = sr.ReadLine();
strData = strLine.Split(delimiter);
DataSet.DataTable.AddDataTableRow(
DateTime.Parse(strData[0]),
strData[1],
   strData[2],
int.Parse(strData[3]),
strData[4]);
}

sr.Close();
}


}


いつも丁寧な回答で協力してくれる皆様には心から感謝しております。
どうぞよろしくお願いします。

駆け出しの初心者です。
以前c言語を少々勉強していてcsvファイルの読み込み、書き出しを練習していたのですが、最近c#を使うようになり、その便利さに圧倒されております。

今回c#で読み込みたいcsvファイルは以下のようになっております
"abc","123","あいうえお"

ただのカンマ区切りであれば読み込みは簡単ですが、
上記のようにダブルクオーテーションでそれぞれの文字列が囲まれている場合に文字列だけを読み込み、配列に代入していくのに何かスムーズな方法はありませんでしょうか?


ちなみに...続きを読む

Aベストアンサー

こう応用するとよいです。
以下に全コードを載せておきますが、ポイントはこの一行です。
strData = strLine.Split(delimiter);

strData = CsvToArrayList1(strLine)[0];


private void LoadData() {
string path = "Data.csv";
string[] strData;//分解後の文字用変数
string strLine;//1行分のデータ
Boolean fileExists = System.IO.File.Exists(path);
if(fileExists) {
System.IO.StreamReader sr = new System.IO.StreamReader(path,System.Text.Encoding.Default);
while(sr.Peek() >= 0) {
strLine = sr.ReadLine();
strData = CsvToArrayList1(strLine)[0];//変更点
DataSet.DataTable.AddDataTableRow(
DateTime.Parse(strData[0]),
strData[1],
strData[2],
int.Parse(strData[3]),
strData[4]);
}

sr.Close();
}
}


//参照先<http://dobon.net/vb/dotnet/file/readcsvfile.html>
//参照先だとArrayListを返し値にしていますが使いづらいので、List<string[]>に変更しています。
public static System.Collections.Generic.List<string[]> CsvToArrayList1(string csvText) {
System.Collections.Generic.List<string[]> csvRecords =
new System.Collections.Generic.List<string[]>();

//前後の改行を削除しておく
csvText = csvText.Trim(new char[] { '\r', '\n' });

//一行取り出すための正規表現
System.Text.RegularExpressions.Regex regLine =
new System.Text.RegularExpressions.Regex(
"^.*(?:\\n|$)",
System.Text.RegularExpressions.RegexOptions.Multiline);

//1行のCSVから各フィールドを取得するための正規表現
System.Text.RegularExpressions.Regex regCsv =
new System.Text.RegularExpressions.Regex(
"\\s*(\"(?:[^\"]|\"\")*\"|[^,]*)\\s*,",
System.Text.RegularExpressions.RegexOptions.None);

System.Text.RegularExpressions.Match mLine = regLine.Match(csvText);
while(mLine.Success) {
//一行取り出す
string line = mLine.Value;
//改行記号が"で囲まれているか調べる
while((CountString(line, "\"") % 2) == 1) {
mLine = mLine.NextMatch();
if(!mLine.Success) {
throw new ApplicationException("不正なCSV");
}
line += mLine.Value;
}
//行の最後の改行記号を削除
line = line.TrimEnd(new char[] { '\r', '\n' });
//最後に「,」をつける
line += ",";

//1つの行からフィールドを取り出す
System.Collections.Generic.List<string> csvFields =
new System.Collections.Generic.List<string>();
System.Text.RegularExpressions.Match m = regCsv.Match(line);
while(m.Success) {
string field = m.Groups[1].Value;
//前後の空白を削除
field = field.Trim();
//"で囲まれている時
if(field.StartsWith("\"") && field.EndsWith("\"")) {
//前後の"を取る
field = field.Substring(1, field.Length - 2);
//「""」を「"」にする
field = field.Replace("\"\"", "\"");
}
csvFields.Add(field);
m = m.NextMatch();
}

csvFields.TrimExcess();
csvRecords.Add(csvFields.ToArray());

mLine = mLine.NextMatch();
}

csvRecords.TrimExcess();
return csvRecords;
}

/// <summary>
/// 指定された文字列内にある文字列が幾つあるか数える
/// </summary>
/// <param name="strInput">strFindが幾つあるか数える文字列</param>
/// <param name="strFind">数える文字列</param>
/// <returns>strInput内にstrFindが幾つあったか</returns>
public static int CountString(string strInput, string strFind) {
int foundCount = 0;
int sPos = strInput.IndexOf(strFind);
while(sPos > -1) {
foundCount++;
sPos = strInput.IndexOf(strFind, sPos + 1);
}

return foundCount;
}

こう応用するとよいです。
以下に全コードを載せておきますが、ポイントはこの一行です。
strData = strLine.Split(delimiter);

strData = CsvToArrayList1(strLine)[0];


private void LoadData() {
string path = "Data.csv";
string[] strData;//分解後の文字用変数
string strLine;//1行分のデータ
Boolean fileExists = System.IO.File.Exists(path);
if(fileExists) {
System.IO.StreamReader sr = new System.IO.StreamReader(path,System.Text.Encoding.Default);
while(sr.Peek() >= 0...続きを読む

QC#で構造体の配列を持った構造体を使いたいのですが

C#で構造体の配列を持った構造体を使いたいのですが
Cならば
struct xyz {
struct abc _abc[32];
int index;
};
struct abc {
int a;
int b;
int c;
};

struct xyz _xyz[8];
xyz[0]._abc[3].b = 1;

のような使い方で という感じで やっていた事を C#で 同じような事をやろうとしても うまくいきません
うまくやる方法をどなたかご存知ないでしょうか

Visual Studio 2005行った場合
コンパイルで
構文エラーです。不適切な配列の宣言子です。マネージ配列を宣言するには、次元指定子を変数の識別子の前に指定します。固定サイズ バッファ フィールドを宣言するには、フィールド型の前に fixed キーワードを使用します
となり

fixed をつけると

固定サイズ バッファの型は次のうちの 1 つでなければなりません: bool、byte、short、int、long、char、sbyte、ushort、uint、ulong、float または double

となってしまいます

C#で構造体の配列を持った構造体を使いたいのですが
Cならば
struct xyz {
struct abc _abc[32];
int index;
};
struct abc {
int a;
int b;
int c;
};

struct xyz _xyz[8];
xyz[0]._abc[3].b = 1;

のような使い方で という感じで やっていた事を C#で 同じような事をやろうとしても うまくいきません
うまくやる方法をどなたかご存知ないでしょうか

Visual Studio 2005行った場合
コンパイルで
構文エラーです。不適切な配列の宣言子です。マネージ配列を宣言するに...続きを読む

Aベストアンサー

C# では、配列は「単なる連続したメモリ領域」ではなくて「添字によってオブジェクトを格納できるオブジェクト」であることに注意しなくてはいけません。つまり、C では配列は一種の構造体でしたが、C# では配列は参照型のオブジェクトです。
よって、C のように予めサイズを固定しておくということは基本的にできません。配列の大きさは配列のインスタンスが作られるときに動的に決まります。

C# では、参照型のオブジェクトを構造体のメンバにすることはあまりありません。null 値の扱いが面倒だからです。
また、C# では構造体の大きさは大きくとも 20 バイト程度までにします。C# では基本的に「構造体へのポインタ」はありません。巨大な構造体をそのまま扱うのはメモリの使い方の観点からいって非効率的です。

今回の件では、構造体ではなくクラスにするのがよいかと思われます。

QC言語で文字列をかえす正しい書き方が知りたいです?

C言語で次の警告が表示されます。
文字列を返したいのですが、正しい書き方はどのようにすれば良いのでしょうか?


jci.h(20) : warning C4172; ローカル変数またはテンポラリのアドレスを返します。


char *test(char *a, int b)
{
char str[BUFSIZ];
return str; <------

}

Aベストアンサー

再入可能にするかどうかで、回答は変わります。

A.2度呼び出した場合に前のデータを破壊してもよいケース(再入不可能)

char *test(...)
{
static char str[BUFSIZ]; // static指定でメモリは静的に確保されます。

...

return str;
}

B.2度呼び出した場合に前のデータを破壊しないケース(再入可能)
B-1.mallocを使ってもいいケース
char *test(...)
{
char *str;
str = malloc(BUFSIZ);
if(str == NULL) return NULL; // エラー

...

return str;
}
この場合は、呼び出し元でちゃんとfreeしましょう。

B-2.呼び出し元でメモリを確保するケース
(注意:同じアドレスを指定して複数回呼び出すと、メモリ内容は当然破壊されます)
char *test(char *str, ...)
{

...

return str;
}
これは#1の方の回答と同じです。

B-3.B-1/B-2の複合
(注意:NULL以外の同じアドレスを指定して複数回呼び出すと、メモリ内容は当然破壊されます)
char *test(char *str, ...)
{
if(str == NULL)
{
str = malloc(BUFSIZ);
if(str == NULL) return NULL; //エラー
}

...

return str;
}

こんなところですかね。

再入可能にするかどうかで、回答は変わります。

A.2度呼び出した場合に前のデータを破壊してもよいケース(再入不可能)

char *test(...)
{
static char str[BUFSIZ]; // static指定でメモリは静的に確保されます。

...

return str;
}

B.2度呼び出した場合に前のデータを破壊しないケース(再入可能)
B-1.mallocを使ってもいいケース
char *test(...)
{
char *str;
str = malloc(BUFSIZ);
if(str == NULL) return NULL; // エラー

...

return str;
}
この場合は、呼び...続きを読む

Qcsvファイルのデータを構造体に

csvファイルのカンマを数えて任意の文字列を抜き出すまでは出来たのですがそこから構造体に格納するまでがこちらのサイトでも検索しましたがよくわかりません。
ご指摘のほどよろしくお願いします。
csvデータ
番号,名前,住所,電話,年齢,性別
1,佐藤,東京,1234,33,A
2,田中,,5678,22,
3,坂井,名古屋,,,B


番号,住所,電話,年齢を格納する場合
struct k_data {
char no[4];/* 出来れば番号を右詰めにしたい */
char add[20];
int tel;
int age;
} kaiin[256];
/* 文字列を抜き出す↓ */
int main(void)
{
FILE *fp1,*fp2;
char dat[256];
char *ch;
int cnt;

/* fp1 ファイルオープン */
/* fp2 ファイルクローズ */

while (fgets(dat, 256, fp1) != NULL) {
cnt = 0;
for (ch = dat; *ch != '\0'; ch++) {
if (*ch ==',') {
if (cnt == 0) {
putc(*ch, fp2);
}
if (cnt == 2) {
putc(*ch, fp2);
}
if (cnt == 3) {
putc(*ch, fp2);
}
if (cnt == 4) {
putc('\n', fp2);
}
cnt++;
} else {
if (cnt == 0) {
putc(*ch, fp2);
}
if (cnt == 2) {
putc(*ch, fp2);
}
if (cnt == 3) {
putc(*ch, fp2);
}
if (cnt == 4) {
putc(*ch, fp2);
}
}
}
putc('\0', fp2);
}
fclose(fp2);
fclose(fp1);
}

csvファイルのカンマを数えて任意の文字列を抜き出すまでは出来たのですがそこから構造体に格納するまでがこちらのサイトでも検索しましたがよくわかりません。
ご指摘のほどよろしくお願いします。
csvデータ
番号,名前,住所,電話,年齢,性別
1,佐藤,東京,1234,33,A
2,田中,,5678,22,
3,坂井,名古屋,,,B


番号,住所,電話,年齢を格納する場合
struct k_data {
char no[4];/* 出来れば番号を右詰めにしたい */
char add[20];
int tel;
int age;
} kaiin[256];
/...続きを読む

Aベストアンサー

まず、取得データをファイルに書き込むのではなく、内部に格納バッファを用意してそこに一時バッファとして格納してください。
CSV仕様上、改行('\n')が要素の終端を表しますので、まず、CSVファイルから1行づつバッファに読み込み、そのバッファデータからカンマ検索実施の上各構造体メンバにセットすればよいと思います。


人気Q&Aランキング