-1

UNIXのwcコマンドの簡単な実装を行っていますが、非常に奇妙な問題があります。49行目のprintfを削除すると、プログラムが正しく動作しません。私は多くのことを試みましたが、どれもうまくいきませんでした。プログラムは動作しますが、出力は私が必要としているものではありません。

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include <string.h>
#include<errno.h>
#include<sys/stat.h>

int *counter(FILE* file) {

    // Function counter - counts the number of lines, words and symbols
    int nsymbols = 0, nwords = 0, nlines = 0;
    char c;
    while (EOF != (c = fgetc(file))) {
        nsymbols++;
        if(c == ' '){
            nwords++;
        }
        if(c == '\n'){
            nlines++;
            nwords++;
        }
    }
    int count[] = {nlines, nwords, nsymbols};
    return count;
}

int main(int argc,char* argv[]) {
    if(argc == 1) {
        int *counted;
        counted = counter(stdin);
        printf("\t%d \t%d \t%d\n", counted[0], counted[1], counted[2]);
    }
    else{
        int i,k, bool = 0;
        int total[] = {0,0,0};
        char c = ' ', w = ' ', l = ' ';

        for(i = 1; i < argc; i++) {

            // Cheking if there are some options activated
            if(strchr(argv[i], '-')){
                if(strcmp(argv[i], "-")==0){
                    continue;
                }
                if(strchr(argv[i], 'l')) {
                    l = 'l';
                }
                if(strchr(argv[i], 'w')) {
                    w = 'w';
                }
                if(strchr(argv[i], 'c')){
                    c = 'c';
                }
                bool = 1;
            }
        }
        if(!bool) {
            // If none of them are activated from the user, automatically activates all of them
            l = 'l';
            w = 'w';
            c = 'c';
        }
        printf("%c %c %c", l,w,c);

        for(i = 1; i<argc; i++){

            if(strcmp(argv[i], "-") == 0){
                int *counted;
                counted = counter(stdin);
                for(k = 0; k < 3; k++){
                    total[k] += counted[k];
                }
                if(l == 'l')
                    printf("\t%d", counted[0]);
                if(w == 'w')
                    printf("\t%d", counted[1]);
                if(c == 'c') {
                    printf("\t%d", counted[2]);
                }
                printf(" %s\n", "-");
            }
            else{
                if(strchr(argv[i], '-'))
                    continue;
                FILE* file = fopen(argv[i], "r");
                if(file == NULL) {
                    fprintf(stderr, "%s : %s\n", argv[i], strerror(errno));
                    return 1;
                }
                struct stat checker;

                if(stat(argv[i], &checker) < 0 ) {
                    return 2;
                }

                if(checker.st_mode & S_IRUSR) {
                }
                else{
                    fprintf(stderr, "%s : %s\n", argv[i],strerror(EACCES));
                    return 3;
                }

                int *counted;
                counted = counter(file);

                for(k = 0; k < 3; k++){
                    total[k] += counted[k];
                }

                if(l == 'l')
                    printf("\t%d", counted[0]);
                if(w == 'w')
                    printf("\t%d", counted[1]);
                if(c == 'c') {
                    printf("\t%d", counted[2]);
                }
                printf(" %s\n", argv[i]);
            }
        }
        if(l == 'l')
            printf("\t%d", total[0]);
        if(w == 'w')
            printf("\t%d", total[1]);
        if(c == 'c') {
            printf("\t%d", total[2]);
        }
        printf(" total\n");
    }
    return 0;
}
4

4 に答える 4

1

それがインプレースで機能する理由printfは偶然です。ローカルへのポインタを返しているため、プログラムの動作は未定義です。ローカル変数に割り当てられたメモリは、関数から戻ったときに再利用されるため、関数の外部でそのメモリを参照すると、ガベージ値にアクセスすることになります。ただし、呼び出し元がスタックを使用している方法が原因で、特定のスポットが再利用されない場合があります。この場合、プログラムは機能しているように見えますが、コードにわずかな変更を加えただけでも、誤った結果が生成されたり、クラッシュしたりする可能性があります。

次のようにコードを変更します。

void counter(FILE* file, int count[]) {
    int nsymbols = 0, nwords = 0, nlines = 0;
    char c;
    while (EOF != (c = fgetc(file))) {
         nsymbols++;
         if(c == ' '){
            nwords++;
         }
         if(c == '\n'){
            nlines++;
            nwords++;
         }
      }
      count[0] = nlines;
      count[1] = nwords;
      count[2] = nsymbols;
}

この関数を次のように呼び出します。

int counted[3];
counter(file, counted);

これで問題が解決します。

于 2013-03-26T13:21:32.253 に答える
0

ここのcount配列

  int count[] = {nlines, nwords, nsymbols};
  return count;

スコープ外になり、関数が戻った後にその存続期間が終了します。メモリを静的またはmallocにすることができます。どちらの場合も、ポイントされたメモリの寿命が関数の実行時間を超えて延長されます。

于 2013-03-26T13:21:44.433 に答える
0

count問題は、ローカル配列である配列を返すことです。あなたはそれをすることはできません。私は未定義の行動になります。すべてが起こる可能性があります!

配列のサイズは固定されているようです。そのため、配列を宣言して、引数として関数counter()に渡す必要があります。

于 2013-03-26T13:23:46.007 に答える
0

配列を静的にするか、mallocまたはcallocを介した動的メモリ割り当てを使用して作成します...ヒープ内に作成された配列は、プログラムが終了するまで保持されるためです。

于 2013-03-26T14:40:53.497 に答える