gooID利用規約 改定のお知らせ

はじめまして。
今回が初質問となります。
お時間がある方はぜひご回答をよろしくお願いいたしますm(_ _)m

C言語を独学で学んでいるため無知なところが多いです...
やさしく、わかりやすく教えて頂ければ幸いです(>_<)


#include<stdio.h>

typedef struct grades {
int number;
char name[20];
double average;
}record;

int main(void) {
int i;

record student1 = {6,"NODA",52.5};
record student2[5] = { {1,"CHIAKI",78.6},{2,"MINE",57.3},{3,"MIKI",66.4},{4,"OKUYAMA",91.4},{5,"SAKU",89.2} };
record *p;
record *s;
p = &student1;
s = &student2[5];

printf("%d %s %5.1f\n\n", p->number, p->name, p->average);

for(i=0; i<5; i++) {
printf("%d %s %5.1f\n", s->number, s->name, s->average);
}

return 0;
}

上記プログラムを実行しますと以下の結果で出力されてしまいます。
6 NODA 52.5

6 NODA 52.5
6 NODA 52.5
6 NODA 52.5
6 NODA 52.5
6 NODA 52.5


ポインタのとこでつまずいている気がするのですが
具体的にどこが悪いのかが分からずに進めずにいます。
(もしポインタでないならすいません...もしかしたらアロー演算子?)


どうか優しい方、ご回答のほどお願いいたします。

A 回答 (4件)

> s = &student2[5];



これは、 student2[5] (student2配列の添字5の要素)に対して&でアドレスを求めることになります。

student2配列の先頭[0]をポインタに入れるなら、
丁寧に書けば
s = &student2[0] ;
配列とポインタが同等に扱われることを利用すれば
s = student2 ;
です。

record student2[5] と宣言したので、添字は0から4であり、 student2[5]は存在しません。
しかし、Cは「6番目」にあたる領域にアクセスしようとします。今回はたまたまそこに student1 の領域があって、&student2[5] == &student1 になったのでしょう。

5回同じ表示になるのは、ループ中でsが変化していないからです。
    • good
    • 0

余談ですが


record student2[5]
に対して
&student2[5]
は完全に合法です.

まったく本題とは関係ありませんが, ねんのため.
    • good
    • 0

s = &student2[0]; // s = &student2[5];



for(i=0; i<5; s++, i++) { // for(i=0; i<5; i++) {
    • good
    • 0

まずは、「どういう動きが正しいのか」を記載しましょう。



プログラムの内容ではなく、やりたいことが判らないと修正しようがないでしょ?
    • good
    • 0

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

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

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

Q ポインタを使って関数の値のやり取り

c言語の問題なのですが、2つの異なる1次元配列の積をseki関数を使って計算してもうひとつの配列に入れてmain関数で表示するのですが、うまく走りません原因がわかる人がいた教えてください。
作った実行文は、
#include<stdio.h>
int seki(int *pa,int *pb,int *pc);
main(){
int a[]={5,2,3,5,3,2,4,8,9,9,7},b[]={4,3,8,4,6,2,8,9,1,6,4},c[11]={0};
int i,*pa,*pb,*pc;

pa=&a;
pb=&b;
pc=&c;

seki(pa,pb,pc);
for(i=0;i<11;i++)
printf("%d,",*(pc+i));

}
int seki(int *pa,int *pb,int *pc){
int j;
for(j=0;j<11;j++)
*(pc+j)=*(pa+j) * *(pb+j);
}
こんな表示が出てきます。
toi2.c: In function `main':
toi2.c:7: warning: assignment from incompatible pointer type
toi2.c:8: warning: assignment from incompatible pointer type
toi2.c:9: warning: assignment from incompatible pointer type
たぶんmain関数内で書いたseki関数の引数の型に問題があると思うのですが。

c言語の問題なのですが、2つの異なる1次元配列の積をseki関数を使って計算してもうひとつの配列に入れてmain関数で表示するのですが、うまく走りません原因がわかる人がいた教えてください。
作った実行文は、
#include<stdio.h>
int seki(int *pa,int *pb,int *pc);
main(){
int a[]={5,2,3,5,3,2,4,8,9,9,7},b[]={4,3,8,4,6,2,8,9,1,6,4},c[11]={0};
int i,*pa,*pb,*pc;

pa=&a;
pb=&b;
pc=&c;

seki(pa,pb,pc);
for(i=0;i<11;i++)
printf("%d,",*(pc+i));

}
int seki(int *pa,int *pb,i...続きを読む

Aベストアンサー

質問の下に書かれているコンパイルエラーと思われる表示から
そのエラーの原因が読み取ることが出来ます。
ここでの原因は、プログラム中次の3行がエラーであると指摘されています。
7行目:pa=&a;
8行目:pb=&b;
9行目:pc=&c;
それぞれ、どういう状況かというと、
エラーをそのまま訳せば
『ポインタとしての割り当て方がおかしいですよ』
という風に捉えられます。
まず、整数型配列として宣言してあるaという変数があります。
これは、これ自身がポインタであるので
&aという表記では、『ポインタ変数aのポインタ』ということになり、
純粋なポインタ変数paには代入する事ができません。
よって、上のエラーを解消するには、
pa = a;
とすればよいでしょう。
(8,9行目も同様)

Qint型配列の一括初期化

現在、ある配列をfor()でループさせて初期化させていますが、もっと高速に初期化できる方法はないでしょうか?

//配列の初期化
int Xi[256];

for(i = 0; i < 256; i++){
   Xi[i] = 0;
}

今後、配列数を増やす予定なので高速に初期化できるものはないか探しています。
速度重視でよろしくお願いします。

Aベストアンサー

全ての要素が0で初期化された配列を確保したいのであれば、calloc()を使うというのはどうでしょうか? 上記のコードより速いという保証はありませんが。

#include <stdlib.h>
int *Xi = (int *)calloc(256, sizeof(int));

配列が不要になった時点でfree(Xi)するのをお忘れなく。また、初期値が0以外の場合にはこの手は使えません。

Qコンパイルエラー invalid operands to binary

自己啓発で入力文字列をBASE64デコードする関数を作っているのですが、L20~L23(a[0] = strchr(b64, p[0]) - b64;)でコンパイルエラーinvalid operands to binaryが発生して色々試行錯誤しているのですが、どうしてもエラーがとれません。
ソースをここに書くのは大変恐縮なのですが、原因がわかる方がいらっしゃいましたら、教えていただけないでしょうか?

char *Base64n(unsigned char *buf, size_t length, size_t *outlen)
{
const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst         uvwxyz0123456789+/=";
unsigned char *p;
unsigned char *q;
unsigned char a[4];
char *RtnBuf;
int j=0;
int cnt;

RtnBuf = (char *)malloc(length+1);
memset(RtnBuf, 0, length+1);

p = (unsigned char*)buf;
q = (unsigned char*)RtnBuf;
cnt = 0;
while(*p != 0) {
a[0] = a[1] = a[2] = a[3] = 0;
a[0] = strchr(b64, p[0]) - b64;
a[1] = strchr(b64, p[1]) - b64;
a[2] = strchr(b64, p[2]) - b64;
a[3] = strchr(b64, p[3]) - b64;

q[0] = ((a[0] << 2) | (a[1] >> 4)) & 0xff;
cnt++;

if (p[2] != '=') {
q[1] = ((a[1] << 4) | (a[2] >> 2)) &0xff;
cnt++;
}
if (p[3] != '=') {
q[2] = ((a[2] << 6) | a[3]) & 0xff;
cnt++;
}
p += 4;
q += 3;
}
*outlen = cnt;
return(RtnBuf);
}

コンパイルはRed Hatでgccを使ってコンパイルしています。
引数は第1引数がデコード対象の文字列、第2引数がデコード対象文字列長、第3引数がデコード後の文字列長で、戻り値がデコード後の文字列です。

自己啓発で入力文字列をBASE64デコードする関数を作っているのですが、L20~L23(a[0] = strchr(b64, p[0]) - b64;)でコンパイルエラーinvalid operands to binaryが発生して色々試行錯誤しているのですが、どうしてもエラーがとれません。
ソースをここに書くのは大変恐縮なのですが、原因がわかる方がいらっしゃいましたら、教えていただけないでしょうか?

char *Base64n(unsigned char *buf, size_t length, size_t *outlen)
{
const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst ...続きを読む

Aベストアンサー

手元にgccが無いので、Windowsのbcc32でコンパイルしてみたところ、
エラーが出ずに通ってしまいました。
だから自信がないのですが…。

a[0] = strchr(b64, p[0]) - b64;



a[0] = strchr(b64, p[0]) - b64[0];

に変えてみたらどうでしょう。
"invalid operands to binary"
は、たぶん、マイナスの両側で型が違っていることを
表しているのではないでしょうか。(←これも自信なし)
strchr()が返すのはchar *型ですが、
b64の型は、charの配列型です。
型が違うので、コンパイラが不正と判断したのかもしれません。

とするとbcc32でなぜ通ったかが問題になるのですが…。
C言語規格でも、ポインタ同士の引き算のところは
ややこしくなっています。
規格解釈の違いがあるのかもしれません。

Q構造体の初期化方法について

こんばんわ。
何度も申し訳ありません。

VC++.NET 2003を用いてコンソールプログラミングを行っています。前回この掲示板を利用して複数回実行するプログラムを作成し、そこに構造体を用いたプログラムを作成しました。以下に概要を示します。

グローバルで構造体を宣言しているため、複数回実行を行うプログラムでは前回の値が格納されたままであると思い、毎回実行時に構造体の初期化を行いたいと思っています。

そこで、以下に示します構造体の初期化はどのように記述すればよいのでしょうか?0で初期化したいと思っています。

よろしくお願い致します。

#define MAX 2000
//グローバル
struct tag{
int Npkt;
int gettime;
int rPkt;
int lossPkt;
}rdata[MAX];

main(){
  //for文で複数回実行処理
  for(i=0;i<=5;i++){
  //ここで構造体の初期化を記述する
//例として、5回プログラムを実行する
  }
}

こんばんわ。
何度も申し訳ありません。

VC++.NET 2003を用いてコンソールプログラミングを行っています。前回この掲示板を利用して複数回実行するプログラムを作成し、そこに構造体を用いたプログラムを作成しました。以下に概要を示します。

グローバルで構造体を宣言しているため、複数回実行を行うプログラムでは前回の値が格納されたままであると思い、毎回実行時に構造体の初期化を行いたいと思っています。

そこで、以下に示します構造体の初期化はどのように記述すればよいのでしょうか?0で初...続きを読む

Aベストアンサー

★まとめ
・既に『memset』関数や、『ZeroMemory』関数の回答があるので構造体の全体、1部の
 初期化の記述例を紹介します。
・それと『#include <memory.h>』を記述しないとメモリ関係の関数が利用できません。
 『ZeroMemory』関数の場合は『#include <windows.h>』があればそのまま利用できます。

●構造体全体を初期化
ZeroMemory( rdata, sizeof(rdata) ); または、
memset( rdata, 0, sizeof(rdata) ); です。

●構造体一部を初期化
ZeroMemory( &rdata[i], sizeof(struct tag) ); または、
memset( &rdata[i], 0, sizeof(struct tag) ); です。
※rdata[i]の1データだけ初期化します。

余談:
・『ZeroMemory』関数は Win32 API と分類されていますが、実体は『memset』関数に
 『#define』されているだけです。でも、戻り値を『VOID』型にキャストされているので
 『memset』関数のリターン値を取得できません。→第一引数のアドレスが『memset』関数
 ではリターンします。
・以上。おわり。

参考URL:http://taka.no32.tk/tips/Win32/ZeroMemory.html

★まとめ
・既に『memset』関数や、『ZeroMemory』関数の回答があるので構造体の全体、1部の
 初期化の記述例を紹介します。
・それと『#include <memory.h>』を記述しないとメモリ関係の関数が利用できません。
 『ZeroMemory』関数の場合は『#include <windows.h>』があればそのまま利用できます。

●構造体全体を初期化
ZeroMemory( rdata, sizeof(rdata) ); または、
memset( rdata, 0, sizeof(rdata) ); です。

●構造体一部を初期化
ZeroMemory( &rdata[i], sizeof(struct tag) ); または、
m...続きを読む

QC言語 アロー演算子

このようなプログラムを作りたいのですが上手くいきません。
(入力と出力は必ずアロー演算子を使う。)
<実行例>
番号を入力:1
名前を入力:taro

番号:1
名前:taro
どなたかよろしくお願い致します

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

typedef struct{
int no;
char name[21];
}student;

void in(student *std){
char namae[21];
int bango,i=0;

scanf("%d", &bango);
std->no = bango;

while(1){
namae[i] = getchar();
if((i >= 20 ) || (namae[i] == '\n'))
break;
i++;
}
i++; namae[i] ='\0';
strcpy(std->name,namae);

}

void out(student *std){
printf("%d\n", std->no);
printf("%s\n", std->name);
}

main(){
student person;
in(&person);
out(&person);

return 0;
}

このようなプログラムを作りたいのですが上手くいきません。
(入力と出力は必ずアロー演算子を使う。)
<実行例>
番号を入力:1
名前を入力:taro

番号:1
名前:taro
どなたかよろしくお願い致します

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

typedef struct{
int no;
char name[21];
}student;

void in(student *std){
char namae[21];
int bango,i=0;

scanf("%d", &bango);
std->no = bango;

while(1){
namae[i] = getchar();
if((i >= 20 ) || (...続きを読む

Aベストアンサー

★ほぼ出来ていますが…。
・『in』関数の『while』の次にある『i++』は不要です。
・『while』ブロックの中で『i++』を行っているため必要ありません。
・場所分かりますか?→『in』関数の下から3行目の『i++』です。
・また、『namae[i] = getchar();』の行は、『namae[i] = (char)getchar();』と
 (char)キャストします。
・『while(1){}』は『for(;;){}』とすると警告メッセージが出ません。
・そして、一番重要なのが『scanf』関数の後(std->noの次など)に『fflush』の
 関数で標準入力をフラッシュさせます。
・こうしないとバッファに数字の『1』が溜まったままになってしまいます。

●修正(in関数のみ→他はあっています)
void in( student *std )
{
 char namae[ 21 ];
 int bango, i;
 
 scanf( "%d", &bango );
 std->no = bango;
 fflush( stdin ); ←ここがポイント
 
 for ( i = 0 ; ; i++ ){ ←この方が分かりやすいよ(初期化 ; 条件式 ; 増減式)
  namae[ i ] = (char)getchar();
  
  if( (i >= 20) || (namae[i] == '\n') ){
   break;
  }
 }
 ←ここにあった『i++』は不要です。
 namae[ i ] ='\0';
 strcpy( std->name, namae );
}

最後に:
・『for』文の2つ目の条件式を省略すると無限ループを構成します。
・『while(1)』でもループできますが、警告メッセージなどが出ます。
・よって、無限ループのときは『for(;;){}』という風にすれば良い。→3つ省略可能なのです。
・以上。おわり。

参考URL:http://www.bohyoh.com/CandCPP/C/Library/fflush.html

★ほぼ出来ていますが…。
・『in』関数の『while』の次にある『i++』は不要です。
・『while』ブロックの中で『i++』を行っているため必要ありません。
・場所分かりますか?→『in』関数の下から3行目の『i++』です。
・また、『namae[i] = getchar();』の行は、『namae[i] = (char)getchar();』と
 (char)キャストします。
・『while(1){}』は『for(;;){}』とすると警告メッセージが出ません。
・そして、一番重要なのが『scanf』関数の後(std->noの次など)に『fflush』の
 関数で標準入力をフラッシュ...続きを読む

Qint型の変数値をバイト列としてコピー

あるint型の変数に格納されている情報を、バイト列としてコピーする方法で困っています。

変数の入っている領域をそのままコピーしたいので、memcpyを使うかと思うですが、
コピーされた結果を見ると文字列の並びが逆転しているように見えます。

--サンプルコード抜粋

unsigned int i= 12345;
unsigned char *c;

c = (char *)malloc(sizeof(int));

printf("i_hex=%x\n",i);
memcpy(c,(int *)&i,sizeof(int));

出力結果

i_hex=3039
cの出力結果 3930000000

単純にmemcpyではダメなのでしょうか?

実行環境は、CentOS(32bit)+gccです。よろしくお願いします。

Aベストアンサー

それで正常です。コピーできてます。

39 30 00 00 00

は、1の位が 0x39 で、256の位が 0x30 で、それより上の位が 0 ということです。
左から1の位から順に表示させているので、逆に見えるだけ。

QC++ 構造体の一括初期化 {0}

構造体変数に {0} を代入すると、CString は空文字、 intは0に一括で初期化されるようです。
なんでこんなことが出来るのでしょう?
{0}は何?
仕組みを教えて下さい!!

Aベストアンサー

> 一括初期化関数でも作るしかなさそうですね
static変数を初期化用に用意しておくのはいかが?
http://oshiete.goo.ne.jp/qa/2658268.htmlより
>静的記憶域期間をもつオブジェクトを明示的に初期化しない場合、
>次の規定に従う。
>a) そのオブジェクトの型がポインタ型の場合、空ポインタに初期化する。
>b) そのオブジェクトの型が算術型の場合、(正または符号なしの)0に初期化する。
>c) そのオブジェクトが集成体の場合、各メンバにa)~d)の規定を(再帰的に)
>適用し初期化する。
>d) そのオブジェクトが共用体の場合、最初の名前つきメンバにa)~d)の規定を
>(再帰的に)適用し初期化する。

なので、zero初期化されていることが、規格で保証されます。

typedef struct hoge_struct
{
 int a;
 int b;
} hoge_struct;

static hoge_struct initializer; //初期化用変数。値は変えない。

int main(void)
{
 hoge_struct hoge;
 hoge = initializer;
 return 0;
}
真っ白に何度も初期化したいなら、こんな感じでどうでしょう?
関数を用意して初期化すると、構造体のメンバが増えると関数も修正しないといけない
ですが、これだと関数を変更しなくてすむし。

> 一括初期化関数でも作るしかなさそうですね
static変数を初期化用に用意しておくのはいかが?
http://oshiete.goo.ne.jp/qa/2658268.htmlより
>静的記憶域期間をもつオブジェクトを明示的に初期化しない場合、
>次の規定に従う。
>a) そのオブジェクトの型がポインタ型の場合、空ポインタに初期化する。
>b) そのオブジェクトの型が算術型の場合、(正または符号なしの)0に初期化する。
>c) そのオブジェクトが集成体の場合、各メンバにa)~d)の規定を(再帰的に)
>適用し初期化する。
>d) そのオブジェクトが共用...続きを読む

QC言語 アロー演算子について質問です。

こんにちわ

C言語初心者です。

C言語の教科書を見ていたら
双方向リストへの挿入というところで
struct CELL{
struct CELL *prev;
struct CELL *next;
int value;
}
x->prev=p;
x->next=p->next;
p->next->prev=x;
p->next=x;
という記述がありました。

質問はこの部分で
p->next->prev=x;
アロー演算子が2個つくとどうなるんですか?

出来ればこの双方向リストの例でたとえてもらえるとうれしいです。

よろしくお願いします。

Aベストアンサー

複数の演算子が使われている式を計算する場合、
例1) A # B $ C

どの順番で計算を行うかは、演算子の優先順位と結合規則を元に決まります
例2) 優先順位が # < $ なら A # (B $ C)
例3) 優先順位が # > $ なら (A # B) $ C
例4) 優先順位が同じ、結合規則が「右から左」なら A # (B $ C)
例5) 優先順位が同じ、結合規則が「左から右」なら (A # B) $ C
参考) http://msdn.microsoft.com/ja-jp/library/2bxt6kc4.aspx

ご質問のケースですが、
アロー演算子どうし → 優先順位が同じ、結合規則が「左から右」
ついでにアローと代入 → 優先順位が アロー > 代入
なので、
p->next->prev = x;

(p->next) -> prev = x; // アローは「左から右」

((p->next)->prev) = x; // アロー > 代入

struct CELL* q = p->next;
(q->prev) = x;

意味合い的には、双方向リストの要素 p の次に x を挿入するため、
1. p の次の要素にて
2. 前への参照を
3. x に書き換る
と思われます

複数の演算子が使われている式を計算する場合、
例1) A # B $ C

どの順番で計算を行うかは、演算子の優先順位と結合規則を元に決まります
例2) 優先順位が # < $ なら A # (B $ C)
例3) 優先順位が # > $ なら (A # B) $ C
例4) 優先順位が同じ、結合規則が「右から左」なら A # (B $ C)
例5) 優先順位が同じ、結合規則が「左から右」なら (A # B) $ C
参考) http://msdn.microsoft.com/ja-jp/library/2bxt6kc4.aspx

ご質問のケースですが、
アロー演算子どうし → 優先順位が同じ、結合規則が「左から右」
つい...続きを読む


人気Q&Aランキング

おすすめ情報