2012-04-26 7 views
2

私はこれを理解できません。私のWindowsマシンでCode :: Blocksを使ってこのコードをコンパイルするとうまくいきますが、Cygwinや実際のUnixマシンでMakeをコンパイルしようとすると、私は以下のような奇妙な動作をします。私はtranslate()に "client1.txt"を渡しています。strcatは私の文字列を上書きします

void translate(char* filepath){ 

    char output_filepath[181]; 
    strcpy(output_filepath, filepath); 
    printf("%s\n", output_filepath);  //this prints out "client1.txt" which is correct 
    char* ptr = strcat(output_filepath, ".translated"); 
    printf("%s\n", output_filepath);  //this prints out ".translated" which is wrong 
    printf("%s\n", ptr);     //also prints out ".translated" wrong again 

...more stuff... 
} 

これは、output_filepathでfgetsを使用しようとするとセグメンテーション違反につながります。誰が何が起こっているか知っていますか?もっと説明する必要はありますか? Unixでコンパイルできる必要があります。

ここは全体のプログラムです、私はそれがあまりにも長すぎないといいですね。私の先生が私たちに働きかけてくれたプログラムですが、実行することさえできません。それはちょうど私にセグメンテーションの誤りを与え、私は上記のセクションを追跡しました。

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

struct tparam{ 
int tid; 
}; 

int NTHREADS = 5; 
#define LOOPS   10000 
int qfilled = 0; 
int qin = 0; 
int qout = 0; 
char queue[3000][2][161]; 
char dic[7000][2][161]; 
int dic_size = 0; 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_mutex_t flag_mutex = PTHREAD_MUTEX_INITIALIZER; 

char * dummystatus[10]; 

char * lookup(char * word) 
{ 
int i; 
for(i = 0; i < dic_size; ++i) 
{ 
    if(strcmp(word, dic[i][0])==0) 
     return dic[i][1]; 
} 
return word; 
} 
void translate(char filepath[]) 
{ 
char output_filepath[181]; 
strcpy(output_filepath, filepath); 
strcat(output_filepath, ".translated"); 

FILE * client_file = fopen(filepath,"r"); 
FILE * translated_client_file = fopen(output_filepath,"w"); 
char line [161]; 
char * tmpPtr; 
char * token; 
while((tmpPtr=fgets(line, 160, client_file))!= NULL) { 
    if(strcmp(line,"\n") == 0 || line == NULL) 
     continue; 
    token = strtok_r(line, " \t\n", dummystatus); 

    while(token != NULL && strcmp(token,"\n") != 0){ 
     fputs(lookup(token), translated_client_file); 
     fputs(" ", translated_client_file); 
     token = strtok_r(NULL, " \t\n", dummystatus); 
    } 
    fputs("\n", translated_client_file); 
} 
fclose(client_file); 
} 
void *do_work(void * p) { 
    struct tparam * param = (struct tparam *)p; 

    while(qfilled != 1);//wait for queue to be filled 

    int cindex; 
    while(1){ 
     //check for more clients 
    pthread_mutex_lock(&mutex); 
    if(qout >= qin){ 
    pthread_mutex_unlock(&mutex); 
    break; 
    } 
    //process client 
    cindex = qout; 
    printf("Thread %d is handling client %s\n",param->tid, queue[cindex][1]); 
    qout++; 
    pthread_mutex_unlock(&mutex); 

    char filepath[161]; 
    if(queue[cindex][0][strlen(queue[cindex][0])-1] == '\n') 
     strncpy(filepath,queue[cindex][0],strlen(queue[cindex][0])-1); 
    else 
    strcpy(filepath,queue[cindex][0]); 
    translate(filepath); 
    printf("Thread %d finished handling client %s\n",param->tid, queue[cindex][1]); 

     //usleep(rand()%100000+10000); 
    } 
    pthread_exit(NULL); 
} 

void addDicEntry(char line[]){ 
char * first = strtok_r(line, " \t", dummystatus); 
char * second = strtok_r(NULL, " \t", dummystatus); 
char englishWord[161]; 
if(1==1 || second != NULL) 
{ 
    strcpy(dic[dic_size][0], first); 
    strncpy(englishWord, second, strlen(second)-1); 
    englishWord[strlen(second)-1] = '\0'; 
    strcpy(dic[dic_size][1], englishWord); 
    dic_size++; 
} 
} 

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

srand(time(NULL)); 
    if(argc < 2){ 
printf("No dictionary file provided\n"); 
exit(1); 
    } 
    //read dictionary 
    int i; 
    for(i = 0; i < 10; ++i) 
dummystatus[i] = (char*)malloc(10); 

    FILE * dic_file = fopen(argv[1],"r"); 
    if(dic_file == NULL) 
{ 
printf("Dictionary file does not exist\n"); 
exit(1); 
    } 
    char line [161]; 
    char * tmpPtr; 
    while((tmpPtr=fgets(line, 160, dic_file))!= NULL) { 
if(strcmp(line,"\n") == 0 || strcmp(line,"") == 0 || line == NULL) 
    break; 
addDicEntry(line); 
    } 
    fclose(dic_file); 
    //End read dictionary 

    //Creating threads 
    if(argc >= 3) 
NTHREADS = atoi(argv[2]); 

    pthread_t * threads = (pthread_t *)malloc(NTHREADS*sizeof(pthread_t)); 
    pthread_attr_t attr; 

    pthread_attr_init(&attr); 
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 
    for (i=0; i<NTHREADS; i++) { 
struct tparam * param = (struct tparam *)malloc(sizeof(struct tparam *)*1); 
param->tid = i+1; 
//printf("Thread %d is being created\n",param->tid); 
pthread_create(&threads[i], &attr, &do_work, param); 
    } 
//End creating threads 

    //insert clients in Q 
    FILE * clients_file = fopen("clients.in","r"); 

    char cid_str[10]; 
    while((tmpPtr=fgets(line, 160, clients_file))!= NULL) { 
if(strcmp(line,"\n") == 0 || strcmp(line,"") == 0 || line == NULL) 
    break; 
pthread_mutex_lock(&mutex); 
strcpy(queue[qin][0],line); 
sprintf(cid_str, "%d", qin+1); 
strcpy(queue[qin][1],cid_str); 
qin++; 
pthread_mutex_unlock(&mutex); 
    } 
    fclose(clients_file); 
//for (i=0; i<qin; i++) 
//printf("%s\n", queue[i][0]); 
    qfilled = 1; 
    printf("Q Filled\n"); 
    //End insert clients in Q 

    //printf("Waiting for Threads\n"); 
    for (i=0; i<NTHREADS; i++) 
pthread_join(threads[i], NULL); 
    //printf("Threads Finished\n"); 

    pthread_attr_destroy(&attr); 
    pthread_exit(NULL); 
} 
+0

ここでgccを使ってUnixでテストしたところ、うまくいきました。おそらくあなたはもう少しコンテキスト/情報を提供することができますか? –

+0

だから私はこれをまっすぐにして、出力は "client1.txt \ n.translated \ n.translated"であるが、 "client1.txt \ nclient1.txt.translated \ nclient1.txt.translated"でなければならない?後者は私が得るものです。あなたの場合、 'strcat'の代わりに' strcpy'を呼び出すような音がします。 – Edmund

+0

私はあなたの 'do_work'関数(これは非常にわかりやすい名前を無視します...)では' strncpy'を有界 'strcpy'として使用していることを指摘したいと思います。文字列をヌル終端することが保証されていないためです。これはおそらくここのバグではない、厄介なコーナーケースを作成する可能性がありますが、それを使用しないと考えるべきです。 –

答えて

0

まあ、それは確かにあなたが期待しているように動作するはず。

一つの可能​​な選択肢ではなくsprintfを使用することです:このあなたが(べき)を使用しているものと同じ結果を生成する必要があり

void translate(char *filepath) { 
    char output_filepath[181]; 

    sprintf(output_filepath, "%s.translated", filepath); 
    printf("%s\n", output_filepath); 
} 

が、あなたは、いくつかのバグに実行している場合並べ替え、おそらく別の関数がうまくいくでしょう。クイックテストは私のために働いていることを示していますが、私はかなりstrcpy/strcatを使用してバージョンを確認するので、知ってテストする必要があります。

編集:ここでは完全なデモプログラムです:私にとって

#include <stdio.h> 

void translate(char *filepath) { 
    char output_filepath[181]; 

    sprintf(output_filepath, "%s.translated", filepath); 
    printf("%s\n", output_filepath); 
} 

int main(){ 
    translate("client1"); 
    return 0; 
} 

は、現時点では私は手元のコンパイラ(VC++ 10は、G ++ 4.7)は、これが期待される出力を生成し、( "client1.translated") 。

+0

私はあなたがそこに持っているものを試しましたが、それはまだ上書きされて、私にちょうど ".translated"を与えています。これは意味をなさない! – Sam

+1

@Sam:問題をコンパイルして示す完全なプログラムを投稿できますか? –

+0

Ed。私はstrcatのoutput_filepathが "client1.txt"で、 ".translated"になる前にそれを確信しています。私はstrcatの作品を知っているが、なぜ私にこの問題を与えるのか分からない。 – Sam

1

このような「説明できないほど奇妙な」振る舞いを示すCプログラムは、マルチスレッド化されたプログラムのメモリ破損を実際に示唆しています。したがって、コードのこの部分に「問題を絞り込んで」いる可能性があります。なぜなら、それが症状の発生場所ですが、バグがどこにあるのかは分かりません。

正常なコンテキスト外でtranslate()を実行しようとしましたか? gdbでプログラムを起動し、main()でブレークしてtranslate("client1.txt")を実行します。それは正しく動作しますか?

もしそうなら、これはプログラムの他の部分がメモリを破壊していることを実際に示唆しています。そして、どの部分がコードのすべてを調べるかを調べる唯一の方法、またはコメント内の@jblenersで提案されているようなvalgrindのようなツールを使用する方法です。

+0

translate()を単独のファイルで実行すると、正しい出力が得られます。実際にはメモリの問題があるはずです。私はvalgrindを使用して、私が見つけることができるものを見ようとします。 – Sam

6

私はこの問題が 'あなたの文字列を上書きする'よりも微妙だと思っています。出力行のデータを上書きすることがより重要になります。このコードを試してみてください:MacのOS X 10.7.3上

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

void translate(char* filepath) 
{ 
    char output_filepath[181]; 

    strcpy(output_filepath, filepath); 
    printf("%s\n", output_filepath);  //this prints out "client1.txt" which is correct 
    char* ptr = strcat(output_filepath, ".translated"); 
    printf("%s\n", output_filepath);  //this prints out ".translated" which is wrong 
    printf("%s\n", ptr);     //also prints out ".translated" wrong again 
} 

int main(void) 
{ 
    translate("client1.txt\r"); 
    return(0); 
} 

出力:

client1.txt 
.translated 
.translated 

あなたはこの明らかな難問につながるファイルパス引数文字列の末尾に改行を持っています。

odまたはhdまたは同様のプログラムを使用してプログラムからの出力を供給することができます。鉱山はodxと呼ばれていますが、何も行います(と、それは新しいファイル名だった以外、あなたのプログラムが全く正当な理由なくx39呼ばれました):

$ ./x39 | odx 
0x0000: 63 6C 69 65 6E 74 31 2E 74 78 74 0D 0A 63 6C 69 client1.txt..cli 
0x0010: 65 6E 74 31 2E 74 78 74 0D 2E 74 72 61 6E 73 6C ent1.txt..transl 
0x0020: 61 74 65 64 0A 63 6C 69 65 6E 74 31 2E 74 78 74 ated.client1.txt 
0x0030: 0D 2E 74 72 61 6E 73 6C 61 74 65 64 0A   ..translated. 
0x003D: 
$ 

私は推測していた場合は、ファイル名を読んで(client1.txt )をWindowsボックスで作成し、テキスト転送ではなくバイナリを使ってUnixに転送すると、おそらくgets()という文字列で読み込まれます。

私はメインコードがfgets() —よりもはるかに良いgets()を使用して参照してください参照してください! —しかし、CRLFの行末に対応するための装備はありません。コードでファイル名が正常に開かれたかどうかは確認されません。 (特にディスク上の入力ファイル名がCR '\r'で終了する可能性は非常に低く、オープンがほぼ確実に失敗するため)コアダンプが遅かれ早かれになります。

常に
  • が、常に、ファイルオープン関数は、ファイルストリームポインタまたはファイル記述子を使用する前に成功したことを確認してください。

私を信じてください。あなたが頻繁に使用され、strcat()としてテストされているようなルーチンでバグを見つけ出すことはめったにありません。

関連する問題