我有一個分配的代碼,我想使用通過命令列引數給出的輸入檔案的“本身”相同的名稱創建和打開一個檔案,但具有不同的擴展名(例如:我傳遞檔案“filename.in”在終端中通過 argv,我想創建并打開檔案“filename.out”)。但是,當我在 valgrind 中運行我的程式時,我不斷收到錯誤“大小 1 的無效大小寫入”和其他一些錯誤,我真的看不到它們來自哪里。
代碼:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "roap.h"
int main(int argc, char** argv) {
FILE* filePtr;
LabList* head = NULL;
if (argc != 3) {
printf("Numero de argumentos errado! \n");
exit(EXIT_FAILURE);
}
char flag[] = "-s";
if ( strcmp(argv[1] , flag) != 0 )
{
fprintf(stdout, "Flag '-s' necessária para esta fase do projeto!"); //verifica se a flag -s está presente
exit(EXIT_FAILURE);
}
char *file_arg /*argumento indicado no terminal para referir ao ficheiro*/, *filename /*nome "próprio" do ficheiro*/, *file_arg_aux;
char dot = '.';
char ponto[] = ".";
char *extencao;
int read_ok;
file_arg = (char*) calloc(1, strlen(argv[2]) 1 ); //verifica se de facto a extens?o é .in1
file_arg_aux = (char*) calloc(1, strlen(argv[2]) 1 );
strcpy(file_arg, argv[2]);
strcpy(file_arg_aux, argv[2]);
filename = strtok(file_arg, ponto);
extencao = strrchr(file_arg_aux, dot);
if ((read_ok = strcmp(extencao, ".in1")) != 0 )
{
fprintf(stdout, "Extens?o inválida!");
exit(EXIT_FAILURE);
}
filePtr = fopen(argv[2], "r");
if (filePtr == NULL) {
printf("Erro ao abrir o ficheiro %s !\n", argv[2]);
exit(EXIT_FAILURE);
} else {
head = readLab(filePtr, head);
fclose(filePtr);
}
char extencao_out[] = ".sol1";
FILE* file_out = fopen( strcat(filename, extencao_out) , "w");
Valgrind 輸出:
==123== Invalid write of size 1
==123== at 0x483EC5E: strcat (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==123== by 0x1095B2: main (main.c:60)
==123== Address 0x4a47051 is 0 bytes after a block of size 17 alloc'd
==123== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==123== by 0x10944E: main (main.c:36)
==123==
==123== Syscall param openat(filename) points to unaddressable byte(s)
==123== at 0x4962D1B: open (open64.c:48)
==123== by 0x48E5195: _IO_file_open (fileops.c:189)
==123== by 0x48E5459: _IO_file_fopen@@GLIBC_2.2.5 (fileops.c:281)
==123== by 0x48D7B0D: __fopen_internal (iofopen.c:75)
==123== by 0x48D7B0D: fopen@@GLIBC_2.2.5 (iofopen.c:86)
==123== by 0x1095C1: main (main.c:60)
==123== Address 0x4a47051 is 0 bytes after a block of size 17 alloc'd
==123== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==123== by 0x10944E: main (main.c:36)
第 36 行: file_arg = (char*) calloc(1, strlen(argv[2]) 1 );
第 60 行: FILE* file_out = fopen( strcat(filename, extencao_out) , "w");
uj5u.com熱心網友回復:
這個 ...
file_arg = (char*) calloc(1, strlen(argv[2]) 1 )
... 為 的副本分配完全足夠的空間argv[2],并將其分配給file_arg。這很好,然后就可以了strcpy(file_arg, argv[2])。
鑒于 的價值ponto,這...
filename = strtok(file_arg, ponto);
...file_arg通過'.'用字串終止符覆寫第一個(如果有)來截斷指向的字串,并回傳 (pointer) 的副本file_arg。這本身沒問題。
但是在這里:
FILE* file_out = fopen( strcat(filename, extencao_out) , "w");
,strcat(filename, extencao_out)嘗試附加字串extencao_out( ".sol1")的內容來代替原始擴展名,您已經有點尷尬地驗證了它是".in1". 因為為原始檔案名分配了足夠的空間,沒有更多的空間來容納程式現在試圖構建的更長的空間。正如 Valgrind 告訴你的那樣,分配的空間被一個位元組覆寫。
我建議將宣告移動extencao_out得足夠早,您可以像這樣分配:
file_arg = (char*) calloc(1, strlen(argv[2]) strlen(extencao_out) 1);
這將使您當前的擴展組合過度分配四個位元組,但是
- 四個位元組可以忽略不計;
- 在大約 75% 的時間里,它可能根本不會給系統帶來額外的記憶體負擔;和
- 它將靈活地處理您以后可能想要支持的其他行為變化,例如沒有擴展名的輸入檔案名。
uj5u.com熱心網友回復:
在單獨的行上宣告變數,并帶有注釋;這些中的每一個都是指標,并且沒有宣告/保留任何記憶體。
char* file_arg; /*argumento indicado no terminal para referir ao ficheiro*/
char* filename; /*nome "próprio" do ficheiro*/
char* file_arg_aux;
char* extencao;
在這里,您將記憶體分配給 file_arg,但僅足以容納原始 argv 字串內容(加上空終止符)。由于您稍后會重用此緩沖區,因此您可能只需為將來的需要分配足夠的額外空間。
file_arg = (char*) calloc(1, strlen(argv[2]) 1 ); //verifica se de facto a extens?o é .in1
file_arg_aux = (char*) calloc(1, strlen(argv[2]) 1 );
只需使用 strdup() 而不是 calloc() 和 strcpy(),
strcpy(file_arg, argv[2]);
strcpy(file_arg_aux, argv[2]);
這些函式都找到了“.”/“。” 在檔案名/file_arg 中,您稍后會使用它來附加新的檔案擴展名(extencao?),
filename = strtok(file_arg, ponto);
extencao = strrchr(file_arg_aux, dot);
這是您預期的擴展名,長度為 4,
strcmp(extencao, ".in1")
這是您的新檔案擴展名,長度為 5,
char extencao_out[] = ".sol1";
用足夠的空間構建您的檔案名以保存檔案名和新擴展名,
char* outfilename = calloc( strlen(filename) strlen(extencao_out) 1 );
strcpy(outfilename, filename);
strcat(outfilename, extencao_out);
FILE* file_out = fopen( outfilename, "w");
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/315038.html
