1

私は最近Cを学び始めたので、私の質問が非常に基本的または不明確な場合はお詫びします。

プログラムに3つのコマンドライン値を渡します。(TYPE、LENGTH、VAL)。これらの値を使用して、タイプTYPEおよび長さLENGTHのヒープ上に配列を作成し、すべての要素をVALに初期化します。だから例えば

float 8 4:それぞれの値が4になる8つの要素を持つfloat配列を作成します。

char 4 65:それぞれが「A」の値を持つ4つの要素を持つchar配列を作成します。

長さの決定は簡単です。しかし、配列とVALへのポインタを初期化する方法を決定するのに苦労しています。

以下は私がこれまでに試みたものです(失敗しました)。charポインターを初期化していますが、代わりにfloatまたはintポインターが必要になる可能性があるため、これが正しくないことがわかります。TYPEの最初の文字に基づくswitchステートメントも使用していますが、これは非常にハッキーなようです。

int main (int argc, char *argv[]){

        int LENGTH;
        char *ptr;

        LENGTH = atoi ( argv[2] );


        switch( *argv[1] ){
                case 'f':
                        printf("Type is float\n");
                        ptr = (float *)malloc(LENGTH * sizeof(float));
                        break;
                case 'c':
                        printf("Type is char\n");
                        ptr = (char *)malloc(LENGTH * sizeof(char));
                        break;
                case 'i':
                        printf("Type is int\n");
                        ptr = (int *)malloc(LENGTH * sizeof(int));
                        break;
                default:
                        printf("Unrecognized type");
                        break;
        }

        while( i < arrayLength ){
                *ptr[i] = *argv[3];
                i++;
        }

        free ( ptr );

        return 0;
}

問題の初期化要素に関する問題も確認できます。初期値はTYPEに依存するため、変換する必要があります。

私が疑問に思っているのは、事前にTYPEを知らなくても、ポインタを作成したり、値を初期化したりするにはどうすればよいですか?私はおそらくこの問題を完全に間違った方向から見ているので、アドバイスをいただければ幸いです。

ありがとう

4

3 に答える 3

2

異なる型を保持できる C の変数が必要な場合は、次のような共用体を使用する必要があります。

typedef union {
    float f;
    int i;
    char c;
} arg_type;

次に、宣言された変数arg_type argument;は、共用体の最大のメンバーを保持するのに十分な大きさになります。それらは、構造体メンバーのようにアクセスされます。次に例を示します。

argument.f = 0.0;
argument.c = '\n';
argument.i = 12;

ただし、コンパイラはどちらを使用したかを認識できないため、そこに格納した型を追跡する必要があります。ユニオンが定義されたら、次のことができます

char var_type = 'f';
arg_type *p = mallocLENGTH * sizeof(arg_type);
p[0].f = atof(argv[i])

ただし、これが正しいことを確認するのは一種の苦痛です。例えば:

argument.f = 1234.56;
putchar(argument.c);

コンパイルされますが、その動作は未定義です。多くの場合、特定のタイプで作業するまでは、argv 文字形式のままにし、解析を保存する方が簡単です。

于 2012-12-11T23:06:06.063 に答える
2

これは、あなたが求めたことを実行するために変更されたコードです (以下の注を参照)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for memset()

int main (int argc, char *argv[]){

        int LENGTH;
        int i;

        void *ptr = NULL;

        if(argc < 4)
        {
            fprintf(stderr, "Usage: %s type len data\n", argv[0]);
            return 1;
        }

        LENGTH = atoi ( argv[2] );


        switch( *argv[1] ){
                case 'f':
                        printf("Type is float\n");
                        ptr = (float *)malloc(LENGTH * sizeof(float));
                        for(i = 0; i < LENGTH; i++)   // Cannot use memset in that case: memset(3) only works with integers.
                            ((float *)ptr)[i] = (float)atof(argv[3]);
                        for(i = 0; i < LENGTH; i++)
                            printf("[%d]: %lf\n", i, ((float *)ptr)[i]);
                        break;
                case 'c':
                        printf("Type is char\n");
                        ptr = (char *)malloc(LENGTH * sizeof(char));
                        memset(ptr, (char)atoi(argv[3]), LENGTH);
                        for(i = 0; i < LENGTH; i++)
                            printf("[%d]: %c\n", i, ((char *)ptr)[i]);
                        break;
                case 'i':
                        printf("Type is int\n");
                        ptr = (int *)malloc(LENGTH * sizeof(int));
                        memset(ptr, (int)atoi(argv[3]), LENGTH);
                        for(i = 0; i < LENGTH; i++)
                            printf("[%d]: %d\n", i, ((int *)ptr)[i]);
                        break;
                default:
                        printf("Unrecognized type\n");
                        break;
        }

        if(ptr == NULL)
            return 1;

        free ( ptr );

        return 0;
}

それでも、他の人が指摘したように、そうすることは無意味です。型が使用される理由は、次の 2 つのことを知るためです。

  1. データのサイズ
  2. どう解釈するか

ここで達成しようとしているのは、OS の仕事をしようとする不器用な試みです。

明確にするために:メモリは連続したストレージであり、OSはそれが「割り当てられた」とマークします(のような関数によってmalloc(3))。その場合、プログラムは、何を読み取るか (ポインターは単なるアドレスです)、データをどのように解釈するかを知るために、データの型を認識している必要があります ( はint、 と同じようには格納されませんfloat)。

そのようなこと (データがどのように保存されるか、コンピューターがより一般的にどのように機能するか、C# よりも低いレベル) を学ぶことに本当に興味がある場合は、以下を読むことをお勧めします。

  1. MIPS アセンブリ チュートリアル(Google からの最初の関連する回答、どの MIPS asm コースでも問題ありません)

  2. x86 アセンブリ、第 6 版。あなたがそれにお金を持っているなら。

また、MIPS アセンブリをテストしたい場合、marsは正常に動作する (しかも無料の) MIPS アセンブリ シミュレータです。

人々がまだ C を学ぼうとしているのを見てうれしいです。

于 2012-12-11T23:19:55.587 に答える
1

このような汎用的なものを C で記述するのは困難です。C++ の方が適しています。しかし、C でそれが必要な場合は、float*、int*、char* の 3 つの異なるポインターを宣言します。ユーザー入力に対応するものを割り当てて初期化します。ただし、プログラム全体で選択された型が何であるかを示す変数を持ち歩く必要がありif、配列を使用する必要があるときはいつでもステートメントを使用する必要があることに注意してください。

于 2012-12-11T22:58:25.057 に答える