[英]strcat overwrites my string
我無法弄清楚這一點。 當我在Windows機器上使用Code :: Blocks編譯此代碼時,它工作得很好,但是當我嘗試在Cygwin下使用Make或在學校里的實際Unix機器上對其進行編譯時,我會得到以下奇怪的行為。 我將“ client1.txt”傳遞給了translate()。
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);
}
我懷疑這個問題比“覆蓋字符串”更微妙。 更多的是覆蓋輸出線上的數據的問題。 試試這段代碼:
#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);
}
在Mac OS X 10.7.3上的輸出:
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:
$
如果我不得不猜測,您會從Windows盒中創建的文件中讀取文件名( client1.txt
),然后使用二進制而不是文本傳輸將其傳輸到Unix,並且您可能會使用gets()
讀取,因為這樣會刪除換行符,而不是回車符。
我看到主要代碼正在使用fgets()
-比gets()
好得多! —但它不具備處理CRLF線尾的功能。 您的代碼不會檢查文件名是否已成功打開; 這遲早會導致核心轉儲(尤其是由於磁盤上的輸入文件名不太可能以CR '\\r'
結尾,因此打開幾乎肯定會失敗)。
相信我; 實際上,很少在例程中找到像strcat()
那樣strcat()
使用和測試的錯誤。
表現出這種“無法解釋的怪異”行為的AC程序確實表明某種程度的內存損壞-在多線程程序中更可能出現這種情況。 因此,您可能已經將問題“縮小”到了代碼的這一部分,因為這是出現症狀的地方,而不是錯誤所在。
您是否嘗試過在正常上下文之外運行translate()
? 在gdb中啟動程序,在main()上斷開,然后運行translate("client1.txt")
。 行為是否正確?
如果是的話,這確實表明程序的其他部分正在破壞內存。 找出哪一部分的唯一方法是研究所有代碼,或使用@jbleners在注釋中建議的類似valgrind的工具。
好吧,它當然應該按照您的期望工作。
一種可能的替代方法是改為使用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”)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.