使用C将文件名复制到数组中

使用C将文件名复制到数组中,c,C,我试图找到某一类型目录中的所有文件(此处硬编码为tif)并将它们复制到数组中。一切都编译得很干净(gcc-Wall没有给出错误或警告),但存在一些内存问题。虽然我编写的程序看起来运行得很干净(没有segfaults),但当字符串中有ascii值以外的内容时,有些文件名是奇怪的字符。这导致我使用valgrind运行,它显示了错误(下面的输出),但我无法跟踪实际问题是什么。在某些目录中,valgrind会将其自分段故障(程序在同一目录中干净地运行) 我已经有一段时间没有使用C了,但据我所知(从手册页

我试图找到某一类型目录中的所有文件(此处硬编码为tif)并将它们复制到数组中。一切都编译得很干净(gcc-Wall没有给出错误或警告),但存在一些内存问题。虽然我编写的程序看起来运行得很干净(没有segfaults),但当字符串中有ascii值以外的内容时,有些文件名是奇怪的字符。这导致我使用valgrind运行,它显示了错误(下面的输出),但我无法跟踪实际问题是什么。在某些目录中,valgrind会将其自分段故障(程序在同一目录中干净地运行)

我已经有一段时间没有使用C了,但据我所知(从手册页),strdup应该使用malloc在堆上为字符串的副本分配内存。在我记起strdup函数之前,我曾尝试过完全手动执行,但也出现了同样的错误。我认为我的代码可能有缺陷,并认为strdup函数会处理它,但显然还有其他问题

谁能告诉我我做错了什么

编辑1: 根据请求,我已经添加了程序的完整源代码。另外,对于那些说根据num_文件检查i的人,正如您将看到的,我会提前计算tif文件的数量,这样我就知道将复制到数组中的文件的确切数量,因此无需检查索引


另外,值得注意的是,该程序是在定义了DEBUG#u MAIN的情况下编译的,因此#ifdef DEBUG#u MAIN块中的任何内容都不会运行。未定义其他调试标志。

应检查数组的索引:

i<num_files

i在您的代码中(;entry!=NULL;i++)
的这部分
太危险了,例如,假设
num_files
的值是1000,如果给定目录包含1002个条目,那么您将遇到问题。
将其替换为(;entry!=NULL&&i

,问题是如果您有任何与您的模式不匹配的条目(例如
条目),您将跳过数组中相应的条目。这还意味着您要在
文件名
数组之外写入。仅当文件名匹配时,才应递增
i

对当前目录使用
getcwd()
而不是只使用
,这是可行的,但几乎没有必要

使用
free(dir)
而不是
closedir(dir)
是一场彻头彻尾的灾难

命令行参数处理是不寻常的。正如最初编写的那样,它将接受
-delete
等同于
-d
。那不是好风格

#include <assert.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>

bool ends_with(char *str, char *sub);
int array_find(char *key, char *argv[], int argc);

int array_find(char *key, char *argv[], int argc)
{
    for (int i = 0; i < argc; i++)
    {
        if (strcmp(key, argv[i]) == 0)
            return i;
    }
    return -1;
}

bool ends_with(char *str, char *sub)
{
    if (str == NULL && sub == NULL)
        return true;
    if (str == NULL || sub == NULL)
        return false;
    char *last_instance_of_sub = rindex(str, *sub);
    size_t sub_len = strlen(sub);
    if (last_instance_of_sub == NULL || strlen(last_instance_of_sub) != sub_len)
        return false;
    return strcmp(last_instance_of_sub, sub) == 0;
}

int main(int argc, char *argv[])
{
    int index = array_find("-d", argv, argc);
    char *dirname;
    if (index >= 0)
    {
        dirname = argv[index + 1];
    }
    else
    {
        dirname = getcwd(NULL, 0);
        if (dirname == NULL)
        {
            perror("Error getting current directory name.");
            exit(1);
        }
    }
    DIR *dir = opendir(dirname);
    if (dir == NULL)
    {
        perror(dirname);
        exit(1);
    }
    char suffix[] = ".c";

    printf("dirname = %s\n", dirname);

    struct dirent *entry;
    int num_files = 0;
    while ((entry = readdir(dir)) != NULL)
    {
        if (ends_with(entry->d_name, suffix))
            num_files++;
    }

    if (closedir(dir) != 0)
    {
        perror("Failed to close directory.");
    }

    printf("Num files = %d\n", num_files);

    dir = opendir(dirname);
    if (dir == NULL)
    {
        perror(dirname);
        exit(1);
    }

    char *file_names[num_files];
    int i = 0;
    while ((entry = readdir(dir)) != NULL)
    {
        if (ends_with(entry->d_name, suffix))
        {
            file_names[i] = strdup(entry->d_name);
            if (file_names[i++] == NULL)
            {
                perror("Could not create the filename array.\n");
                exit(1);
            }
        }
    }
    assert(i <= num_files);
    if (i < num_files)
        num_files = i;

    for (i = 0; i < num_files; i++)
    {
        printf("%s\n", file_names[i]);
        free(file_names[i]);
    }

    closedir(dir);
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
bool以(char*str,char*sub)结尾;
int-array_-find(char*key,char*argv[],int-argc);
int数组_find(char*key,char*argv[],int-argc)
{
对于(int i=0;i=0)
{
dirname=argv[index+1];
}
其他的
{
dirname=getcwd(NULL,0);
if(dirname==NULL)
{
perror(“获取当前目录名时出错。”);
出口(1);
}
}
DIR*DIR=opendir(dirname);
if(dir==NULL)
{
perror(dirname);
出口(1);
}
字符后缀[]=“.c”;
printf(“dirname=%s\n”,dirname);
结构方向*条目;
int num_files=0;
while((entry=readdir(dir))!=NULL)
{
if(以(输入->d_名称,后缀)结尾)
num_文件++;
}
if(closedir(dir)!=0)
{
perror(“无法关闭目录”);
}
printf(“Num files=%d\n”,Num\u files);
dir=opendir(dirname);
if(dir==NULL)
{
perror(dirname);
出口(1);
}
char*文件名[num_files];
int i=0;
while((entry=readdir(dir))!=NULL)
{
if(以(输入->d_名称,后缀)结尾)
{
文件名[i]=strdup(条目->文件名);
if(文件名[i++]==NULL)
{
perror(“无法创建文件名数组。\n”);
出口(1);
}
}
}

断言(i
条目的初始值是多少?
?1.如果您发布的是实际的,而不仅仅是一个片段,那么它会有所帮助。2.您的程序是否在仅使用ASCII文件名的目录中工作?3.如果没有相应的源代码(以及与之配套的行号),Valgrind输出根本没有帮助另外,您是否记得使用最终值
i
更新
num\u文件
?是否返回
文件名
数组(使用自动存储类)对于调用者?发布一个完整的示例可以解决所有这些问题,而无需询问。@user4815162342:同意,可能会有大约一百万种不同的错误,从超出范围的结构到多字节字符集问题,再到未正确处理的错误条件。但至少尝试使用+1进行调试valgrind,比我们在这里遇到的大多数问题都要多我有点气愤自己,因为我没有看到我在数组中前进,不管我是否添加了文件。我的调试技能在过去几个月里一塌糊涂。无论如何,谢谢你的帮助,也谢谢你的其他提示,我会考虑它们的。
i<num_files
#include <assert.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>

bool ends_with(char *str, char *sub);
int array_find(char *key, char *argv[], int argc);

int array_find(char *key, char *argv[], int argc)
{
    for (int i = 0; i < argc; i++)
    {
        if (strcmp(key, argv[i]) == 0)
            return i;
    }
    return -1;
}

bool ends_with(char *str, char *sub)
{
    if (str == NULL && sub == NULL)
        return true;
    if (str == NULL || sub == NULL)
        return false;
    char *last_instance_of_sub = rindex(str, *sub);
    size_t sub_len = strlen(sub);
    if (last_instance_of_sub == NULL || strlen(last_instance_of_sub) != sub_len)
        return false;
    return strcmp(last_instance_of_sub, sub) == 0;
}

int main(int argc, char *argv[])
{
    int index = array_find("-d", argv, argc);
    char *dirname;
    if (index >= 0)
    {
        dirname = argv[index + 1];
    }
    else
    {
        dirname = getcwd(NULL, 0);
        if (dirname == NULL)
        {
            perror("Error getting current directory name.");
            exit(1);
        }
    }
    DIR *dir = opendir(dirname);
    if (dir == NULL)
    {
        perror(dirname);
        exit(1);
    }
    char suffix[] = ".c";

    printf("dirname = %s\n", dirname);

    struct dirent *entry;
    int num_files = 0;
    while ((entry = readdir(dir)) != NULL)
    {
        if (ends_with(entry->d_name, suffix))
            num_files++;
    }

    if (closedir(dir) != 0)
    {
        perror("Failed to close directory.");
    }

    printf("Num files = %d\n", num_files);

    dir = opendir(dirname);
    if (dir == NULL)
    {
        perror(dirname);
        exit(1);
    }

    char *file_names[num_files];
    int i = 0;
    while ((entry = readdir(dir)) != NULL)
    {
        if (ends_with(entry->d_name, suffix))
        {
            file_names[i] = strdup(entry->d_name);
            if (file_names[i++] == NULL)
            {
                perror("Could not create the filename array.\n");
                exit(1);
            }
        }
    }
    assert(i <= num_files);
    if (i < num_files)
        num_files = i;

    for (i = 0; i < num_files; i++)
    {
        printf("%s\n", file_names[i]);
        free(file_names[i]);
    }

    closedir(dir);
    return 0;
}