问题
I've got a project about moving certain files from one directory to another. I have all finished except that the output is kind of strange. I am required to provide the destination path in the argsv array, but when I try to execute my code, it compiles and works but shows the wrong path containing many paths in one! Here is the relevant part, if you need more code I will add! Thank you in advance!
int main(int argc, char **argv)
{
int size = NFILES;
int index = -1;
file * files = malloc(size * sizeof(file));
listFilesRecursively(argv[1], &files, &size, &index);
if (index != -1) {
int N = atoi(argv[2]);
if(N==1) qsort(files, index + 1, sizeof(file), compPathname);
else if(N==2) qsort(files, index + 1, sizeof(file), compPathsize);
for (int i = 0; i <= index; ++i) {
char *dest = argv[3];
strcat(dest, "/");
strcat(dest, files[i].justname);
printf("%s : %s : %ld\n", files[i].name, dest , (long) files[i].file_info.st_size);
// if(rename(files[i].name, dest)==0) printf("Success!\n"); else printf("Failed!/n");
}
So this is the main. The desired output is like this (I have many files):
./copyto.c : /home/nik/copyto.c : 676
Success!
./mvfilrd.c : /home/nik/mvfilrd.c : 957
Success!
./sortall.c : /home/nik/sortall.c : 992
Success!
and so on... but instead I get
./newdir/newfile.txt : /home/nik/Music/newfile.txt : 0
Success!
./newdir/3.exe : /home/nik/Music/newfile.txt/3.exe : 0
Failed!/n./newdir/compil : /home/nik/Music/newfile.txt/3.exe/test : 0
Failed!/n./newdir/2.c : /home/nik/Music/newfile.txt/3.exe/test/exe : 0
and then even more garbage
Failed!/n./newf.exe : /home/nik/Music/newfile.txt/3.exe/test/exe /1//Q�/~�dZ /�l�G^ /
��`(/4�a^d /a.txt/range/1.txt/1.exe/print.exe/filrd.exeC/2.exre/filrd.exe/2.exe/fi.txt/fil.txt/dest.txt/sorcopy.c/filew.exe/.filer.c.swp /progfilrd.exe/compile/myfile/.m
and the first argument seems to have crashed as well...
回答1:
char *dest = argv[3];
strcat(dest, "/");
strcat(dest, files[i].justname);
ouch you modify a string you do not own, do not do that, you probably write out of the string, work on a copy
replace
for (int i = 0; i <= index; ++i) {
char *dest = argv[3];
strcat(dest, "/");
strcat(dest, files[i].justname);
printf("%s : %s : %ld\n", files[i].name, dest , (long) files[i].file_info.st_size);
if(rename(files[i].name, dest)==0)
printf("Success!\n");
else
printf("Failed!/n");
}
by
for (int i = 0; i <= index; ++i) {
size_t sz = strlen(argv[3]);
char *dest = malloc(sz + strlen(files[i].justname) + 2);
strcpy(dest, argv[3]);
dest[sz] = '/';
strcpy(dest + sz + 1, files[i].justname);
printf("%s : %s : %ld\n", files[i].name, dest , (long) files[i].file_info.st_size);
if(rename(files[i].name, dest)==0)
printf("Success!\n");
else
printf("Failed!/n");
free(dest);
}
回答2:
This:
char *dest = argv[3]
makes dest
point to the same string that argv[3]
does. That is, you have copied the pointer, not the data to which it points. When you subsequently modify that data through dest
, you are modifying the argument itself. This is allowed, but poor form.
The bigger problem is what you actually do with it. This:
strcat(dest, "/");
strcat(dest, files[i].justname);
attempts to append data to the end of the argument string, but it is unsafe to assume (and it is probably incorrect in practice) that there is any free space in the pointed-to array in which to store the extra characters. If indeed there is not enough space then you produce undefined behavior.
Based on the code you did show and the behavior you describe, I speculate that what you did not show might include a similar assignment of another argument pointer to files[i].justname
. Such an assignment is not inherently wrong, but it could easily make the manifestation of the UB more confusing than it already was.
In any case, if you want to form concatenations of the program arguments, then you need to reserve separate space for the result. You can do that with a large-enough automatic array, or with sufficiently large dynamically-allocated space. The latter might look like this:
size_t path_chars = strlen(argv[3]) + strlen(files[i].justname) + 2;
char *path = malloc(path_chars);
if (path) {
sprintf(path, "%s/%s", argv[3], files[i].justname);
} // else handle memory allocation failure
You can use strcpy()
and strcat()
instead if you prefer, but in this particular case I think sprintf()
is clearer and cleaner.
来源:https://stackoverflow.com/questions/54278697/how-to-properly-pass-file-path-with-from-the-command-line