1

これは私を夢中にさせています。ファイル名のユーザー入力を受け入れるプログラムを作成しました。~/documents/cs ディレクトリで実行すると意図したとおりに動作しますが、 ~/documents/cs/assign5 ディレクトリでは失敗します。これは私にはまったく意味がありません。プログラムが存在するディレクトリに基づいて、プログラムの動作が異なるのはなぜですか?

親ディレクトリでの実行からの良好な出力:

./a.out - file2
Enter the filename: file1
FILE1
FILE2

assign5 ディレクトリからの不正な出力:

./a.out - file2
Enter the filename: file1
file1
n: No such file or directory

assign5 ディレクトリの名前を別の名前に変更してみましたが、うまくいきました。

このプログラムは、基本的に 2 つのコマンド ライン引数を取ります。「-」コマンドライン引数が存在する場合、ファイル名を要求します。次に、両方のファイルの内容を標準出力に出力します。プログラムが失敗している場所は次のとおりです(assign5ディレクトリのみ...)。プログラムが assign5 ディレクトリで実行されると、userInput 変数に「file1」ではなく「n」という値が格納されているようです。どうして!?

if(strcmp(argv[1], "-") == 0) // use standard-in for input file 1
        {
            printf("Enter the filename: ");
            fflush(NULL);
            read(STDIN_FILENO, userInput, sizeof(userInput));
            userInput[strlen(userInput)-1] = '\0';
            if((input_file1 = open(userInput, O_RDONLY)) < 0)
            {
                perror(userInput);
                exit(1);
            }

アップデート:

「assign5」というディレクトリのリモートLinuxサーバーでまったく同じコードを実行したところ、意図したとおりにコンパイルおよび実行されました。それで、何、私のコンピューターに何か問題がありますか?

4

2 に答える 2

4

使用しないでくださいread。自分が何をしているのかわからない限り、すべての I/O が台無しになります。

strlenから返された入力はread、せいぜいSIGSEGVあなたが観察しているように、最悪の場合は未定義の動作につながります。を使用しscanfます。

scanf("%s", userInput); // will add a null terminator itself

本当に使用する必要がある場合は、手動でread作業を行う必要があります。scanf

// reserve space for the null terminator
int bytes_read = read(STDIN_FILENO, userInput, sizeof(userInput) - 1);
if (bytes_read < 0) {
    perror("read");
    abort();
}         

// add the null terminator
userInput[bytes_read] = '\0';

// you will most likely have a newline in the input
while (isspace(userInput[bytes_read - 1]))
     userInput[--bytes_read] = '\0';

char * filename = userInput;

// you may have preceding spaces
while (isspace(*filename))
     filename++;

また、未定義の理由によりread、入力全体が読み取られる前に返される可能性があることに注意してください。その場合、理想的には、0 が返されるまで再度呼び出す必要がありscanfます。

于 2013-11-01T15:14:17.543 に答える
0

私が意図していると思われるように、最後に「\ 0」を追加する代わりに、文字列の最後の文字を「\ 0」に置き換えています。次の行を変更します。

userInput[strlen(userInput)-1] = '\0';  

に:

userInput[strlen(userInput)] = '\0';  

私は Linux や Unix をロードしていませんが、この Windows コードは小さく、私が提案していることをよりよく示しています。

#include <windows.h>
#include <ansi_c.h>
int main(void)
{
    DWORD len=260;
    LPTSTR lpBuffer;
    lpBuffer = malloc(260);
    GetCurrentDirectory(len, lpBuffer);

    lpBuffer[strlen(lpBuffer)]=0; //This works (although not necessary here
                                  //as GetCurrenentDirectory appends a '\0'
                                  //however, it is safe to do)

    lpBuffer[strlen(lpBuffer)-1]=0; //This will destroy the path information
                                    //by removing the last necessary char from 
    return 0;                       //your path string
}
于 2013-11-01T16:07:57.263 に答える