好吧基本上我正在编写一个程序,它接收两个目录并根据提供的选项处理它们。当我没有看到问题时,它会给我分段错误。导致问题的代码如下:
编辑:更新代码以包含我的整个源文件
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#define OPTLIST "am:npruv"
#define DEFAULT_MOD_TIMES 1
typedef struct
{
/* Boolean toggle to indicate whether hidden files should be
processed or not */
bool processHiddens;
/* Integer number of seconds such that files with modification
times that differ by less than this value are considered the
same */
int timeResolution;
/* Boolean toggle to indicate whether the actual synchronisation
(file creation and overwriting) should be performed or not */
bool performSync;
/* Boolean toggle to indicate whether subdirectories should be
recursively processed or not */
bool recursive;
/* Boolean toggle to indicate whether to print the combined
directory structure or not */
bool print;
/* Boolean toggle to indicate whether modification times and
permissions should be updated or not */
bool updateStatus;
/* Boolean toggle to indicate whether verbose output should be
printed or not */
bool verbose;
/* The name of the executable */
char *programname;
} OPTIONS;
int main(int argc, char *argv[])
{
static OPTIONS options;
//static TOPLEVELS tls;
int opt;
char **paths;
/*
* Initialise default without options input.
* Done the long way to be more verbose.
*/
opterr = 0;
options.processHiddens = false;
options.timeResolution = DEFAULT_MOD_TIMES;
options.performSync = true;
options.recursive = false;
options.print = false;
options.updateStatus = true;
options.verbose = false;
options.programname = malloc(BUFSIZ);
options.programname = argv[0];
/*
* Processing options.
*/
while ((opt = getopt(argc, argv, OPTLIST)) != -1)
{
switch (opt)
{
case 'a':
options.processHiddens = !(options.processHiddens);
break;
case 'm':
options.timeResolution = atoi(optarg);
break;
case 'n':
options.performSync = !(options.performSync);
break;
case 'p':
options.print = !(options.print);
break;
case 'r':
options.recursive = !(options.recursive);
break;
case 'u':
options.updateStatus = !(options.updateStatus);
break;
case 'v':
options.verbose = !(options.verbose);
break;
default:
argc = -1;
}
}
/*
* Processing the paths array for top level directory.
*/
char **tempPaths = paths;
while (optind < argc)
{
*tempPaths++ = argv[optind++];
}
if (argc -optind + 1 < 3)
{
fprintf(stderr, "Usage: %s [-amnpruv] dir1 dir2 [dirn ... ]\n", options.programname);
exit(EXIT_FAILURE);
}
else
{
//processTopLevelDirectories(tls, paths, nDirs, options);
exit(EXIT_SUCCESS);
}
return 0;
}
我有一个bash脚本,运行时执行以下操作:
#!/bin/bash
clear
echo Running testing script
echo Removing old TestDirectory
rm -r ./TD
echo Creating new copy of TestDirectory
cp -r ./TestDirectory ./TD
echo Building program
make clean
make
echo Running mysync
./mysync ./TD/Dir1 ./TD/Dir2
echo Finished running testing script
但是,如果我尝试使用完全相同的命令手动运行程序:
./mysync ./TD/Dir1 ./TD/Dir2
我在test1和test2之间遇到了分段错误。但是,如果我要将/
附加到任何一个目录,或两者,那么它再次起作用。任何想法的家伙?
答案 0 :(得分:9)
您需要使用strcpy()
将argv[optind]
复制到您刚刚分配的*tempPaths
空间。
实际上,你正在摧毁(泄漏)你分配的内存,然后谁知道还有什么问题。
另外,为什么你需要复制你的论点?如果您不修改它们,则无需复制它们。
char **tempPaths = paths;
while (optind < argc)
{
printf("test1\n");
// Or use strdup(), but strdup() is POSIX, not Standard C
// This wastes less space on short names and works correctly on long names.
*tempPaths = malloc(strlen(argv[optind])+1);
// Error check omitted!
strcpy(*tempPaths, argv[optind]);
printf("test2\n");
printf("%s\n", *tempPaths);
tempPaths++;
optind++;
}
这假设您确实需要复制您的参数。如果您不需要修改命令行参数,则只需使用:
char **tempPaths = paths;
while (optind < argc)
*tempPaths++ = argv[optind++];
当我编辑删除不再需要的内容时,那里的代码就消失了......
甚至可以简单地设置:
char **paths = &argv[optind];
这完全取消了循环和临时变量!
当你说我分配的内存泄漏时,你的意思是什么?
您的原始代码是:
*tempPaths = malloc(BUFSIZ);
*tempPaths = argv[optind];
第一个语句将内存分配给* tempPaths;第二个然后用指针argv [optind]覆盖指针(唯一的引用),从而确保你不能释放分配的内存,并确保你不使用它。此外,如果您随后尝试释放...指向的内存,那么在此阶段它将是paths
而不是tempPaths
...然后您尝试释放从未分配的内存,这也是一件坏事™。
此外,我并不特别明白你的意思是“复制你的论点”。您是指的是用于命令行的两个目录还是其他目录?
您的代码正在复制传递给程序的参数(目录名称);使用strdup()
(或大致是strdup()
的主体)的修订解决方案会在argv[optind]
中复制数据。但是,如果您要对数据进行所有操作而不更改它,则可以简单地复制指针,而不是复制数据。 (即使你要修改参数,如果你小心,你仍然可以使用原始数据 - 但是制作副本更安全。)
最后不会char ** paths =&amp; argv [optind];只给我一个目录,就是这样吗?
没有;它会给你一个指向以空字符结尾的字符串指针列表的指针,你可以单步执行:
for (i = 0; paths[i] != 0; i++)
printf("name[%d] = %s\n", i, paths[i]);
如评论中所述,扩展崩溃代码的基本问题(除了我们没有标题的事实)是paths
变量未初始化为指向任何内容。毫无疑问,代码会崩溃。
基于修改后的示例 - 选项处理被删除:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char **paths;
optind = 1;
paths = &argv[optind];
if (argc - optind + 1 < 3)
{
fprintf(stderr, "Usage: %s dir1 dir2 [dirn ... ]\n", argv[0]);
exit(EXIT_FAILURE);
}
else
{
char **tmp = paths;
while (*tmp != 0)
printf("<<%s>>\n", *tmp++);
}
return 0;
}
此版本进行内存分配:
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
optind = 1;
if (argc - optind + 1 < 3)
{
fprintf(stderr, "Usage: %s dir1 dir2 [dirn ... ]\n", argv[0]);
exit(EXIT_FAILURE);
}
else
{
int npaths = argc - optind;
char **paths = malloc(npaths * sizeof(*paths));
// Check allocation!
char **tmp = paths;
int i;
printf("n = %d\n", npaths);
for (i = optind; i < argc; i++)
{
*tmp = malloc(strlen(argv[i])+1);
// Check allocation!
strcpy(*tmp, argv[i]);
tmp++;
}
for (i = 0; i < npaths; i++)
printf("<<%s>>\n", paths[i]);
}
return 0;
}
答案 1 :(得分:0)
您已确定在以下某行中发生了段错误:
*tempPaths = malloc(BUFSIZ);
*tempPaths = argv[optind];
argc
中的条目少于argv
次的可能性极小,因此我们推断问题是*tempPaths
的分配,因此tempPaths
无法生效指针。
由于您没有展示paths
如何初始化,因此无法深入挖掘。最有可能argc
中的成员少于paths
,因此您的tempPaths++
会导致您移动到最后一个条目。