2012-02-24 15 views
0

非常に基本的な作業、つまり配列のサイズを変更することには多くの問題があります。私がこれまでに学んだプログラミングクラスのすべてのイントロは、より大きな配列を作成し、それを充填し、元の配列を新しい(より大きな)配列に向けることによってこれを行うよう教えてくれました。文字ポインタのポインタへのポインタ、またはこの配列を再割り当てできないのはなぜですか?

以下のプログラムは、文字列をプログラム名とそのargv []にトークン化します(最終的に基本的なシェルの実装になります)。一度に8つの引数のためのスペースを割り当てます。もし8以上のものがあれば、それは再帰的に大きな配列を割り当てて、それを埋めます。

args配列からmoreArgs配列を指すことができない点を除いて、すべてうまくいっています(他にも教えてください)。私はgetArgs関数の最後にこれを行うべきですが、単にargs []のアドレスを再割り当てしないという声明があります。私は間違って何をしていますか?

#define debug 1 

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

char ** getArgs(char *input, char **args, int ct); 

/*Is there a better way than making these global?*/ 
char ** args; 
char **moreArgs; 

int main(int argc, char* argv[]) { 
    char input[]="echo arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 arg10"; 
    char inputcpy[strlen(input)]; 
    strcpy(inputcpy, input); 
    char * temp; 
    temp=strtok(input, " "); 
    char * prog=temp; 

    args=(char **) calloc(8, sizeof(char*)); 

    getArgs(inputcpy, args, 1); 

    if(debug) { 
    printf("arg address after: %p\n", args); 
    printf("morearg address after func: %p\n", moreArgs); 
    } 

    /*This is basically what the shell will look like. The actual implementation will use stdin 
    for input. (Unless a pipe or < is present in the input)*/ 
    int q; 
    int pid=fork(); 
    if (pid!=0) { 
    execvp(prog, args); //when moreArgs!=null, args should point to moreArgs 
    return 0; 
    } 
    else { 
    int status=0; 
    wait(&status); 
    } 
} 


/*This function should takes the first argument and inserts int into the second as " " separated tokens. If the second argument is too small -- the function recurses, and resizes the array as needed. The third argument is used to keep 
    track of the recursion*/ 
char ** getArgs(char *input, char **args, int ct) { 
    int adj=(ct-1)*8;//if we recurse, this ensures correct indexes are used 
    char *inputcpy=malloc(strlen(input)); 
    strcpy(inputcpy, input); 

    /*Initialize indexes/Prepare for copying*/ 
    int i; 
    if(ct==1) { 
    i=1; // this might throw off later adjusts 
    args[0]=" "; //quick hack to ensure all args are used by exec() 
    } 
    else 
    i=0; 

    /**Actually do the copying now**/ 
    char *temp=strtok(NULL, " "); //What if later tokens are longer? 
    args[adj+i++]=temp; 

    while (temp != NULL && i<8) { 
    temp=strtok(NULL, " "); 
    args[adj+i++]=temp; 
    } 

    /*If there are more args than we have room for*/ 
    if(i>=8){ 

    //is this allocation right? 
    moreArgs = (char **) malloc((++ct)*8*sizeof(char *)); 

    /*Fill moreArgs with args*/ 
    int j; 
    for (j=0; /*j<ct*8 && */args[j]!=NULL; j++) { 
     moreArgs[j]=args[j]; 
    } 

    getArgs(inputcpy, moreArgs, (ct)); //could probably move inc to malloc 

    //free(args)?  
    if(ct>1) 
     args=moreArgs; 
    } 
    /*Done with too many args problem*/ 


    return NULL;//(char **) args; //we don't want the global args though 
} 
+2

'realloc()'はあなたの友人です... –

+0

私はコードをスキミングしましたが、 'calloc'はポインタ型を' NULL'ポインタに初期化することは技術的に保証されていません。整数の場合は数値ゼロを意味するオール・ビット・ゼロに初期化し、ヌル・ポインタが数値ゼロのプラットフォームの場合は「NULL」を初期化しますが、C言語レベルでゼロがNULLを保証する場合でもNULLポインターの機械語レベル表現は、「全ビット・ゼロ」であるとは保証されない。あなたのコードが 'calloc'-edポインタが' NULL'であるかどうかは分かりませんが、実際には間違っているとすれば、それは正しくありません。 –

+0

@ChrisLutzうわー、私たちが対処しなければならないこと... –

答えて

1

それはあなたが値によってargsを渡しているので、それがあるために望むように動作していない理由。

char ** getArgs(char *input, char ***args, int ct); 

この方法で、あなたはargsを再割り当てすることができます。

編集:再割り当てする前にargsを解放してください。編集2:それは私にはあまりにも特異でした。 すべてを動的に割り当てたオブジェクトを解放してください。ちょうどあなたが残したことはかなりあります。

親プロセスからexecvpを呼び出し、子プロセスからwaitを呼び出しています。それは別の方法です。また、forkexecvpとし、代わりにsystemを使用することは避けてください。あなたはそれが原子的操作であるという利点を得る。

+0

お返事ありがとうございます。私はいくつかのフォローアップがあります(申し訳ありません、私はCを学んでいます)。その宣言の下で、&argsを渡すか、argをchar *として宣言しなければなりませんか?そうでなければ* argsを参照しますか?また、Cの全学期の後、私はちょうどメモリリークについて知りました。私が知る限り、動的に割り当てられるオブジェクトはtemp、args、moreArgsの3つです。私が自由にするべきことは何か他にありますか?最後に、あなたはシステムとフォークについてより明確になりますか?フォークしないと、execvpは親プログラムを上書きしますか? – user1209326

+0

あなたは '&args'を渡し、関数本体でそれにアクセスするときには逆参照する必要があります。 '* args = moreArgs;'割り当てられた記憶域を持つオブジェクトは 'args'、' moreArgs'、 'inputcpy'です。 'temp'はそれらの一つではありません。あなたは 'malloc()'/'calloc()'を呼び出すことによって初期化されていることが分かります。私は自分自身をフォークし、実行し、待っているのではなく、 'system()'を呼び出すべきだと言っています。利点は、それが原子操作であることです。 – someguy

+0

ご協力いただきありがとうございます。私は自分の損失をカットし、realloc()で書き直しましたが、あなたの投稿は本当に役に立ちました! – user1209326

関連する問題