Stack Overflow上有很多类似的帖子,我仔细阅读了这些帖子,并将它们链接到本文末尾。这些现有的帖子没有帮助,因为它们演示了由于将未初始化的内存部分传递给strncpy()
函数的char *dest
参数而导致的段错误。这些帖子中另一个常见的主题是强烈建议不要使用strncpy()
,但我读到的唯一替代建议是使用strlcpy()
。
我的程序使用一个静态分配的FS_Info
结构数组来存储有关文件系统项的信息。其思想是输出指定目录中最大的10个文件的名称和大小。由于数组的大小是固定的,当发现一个文件系统条目大于数组中最小的条目时,我的程序尝试用描述新的更大条目的值来更新描述这个较小条目的结构体。
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
// size of array used to contain filesystem entries
const size_t fs_info_arr_size = 10;
// A struct to contain the name of a filesystem entry and its size in bytes.
typedef struct FS_Info
{
char name[PATH_MAX];
long long size;
} FS_Info;
// global pointer to FS_Info array
FS_Info *fs_info_arr[fs_info_arr_size];
// used to sort fs_entries array descending in terms of entry size
static int compare(const void *a, const void *b)
{
const struct FS_Info *entryA = (FS_Info *)a;
const struct FS_Info *entryB = (FS_Info *)b;
return (entryB->size - entryA->size) - (entryA->size - entryB->size);
}
/*
Iterates over an array of FS_Info structs and returns a pointer to the struct having the smallest size member
*/
FS_Info *get_smallest_entry(FS_Info **entries)
{
long long smallest = entries[0]->size;
FS_Info *target;
for (int i = 1; i < fs_info_arr_size * sizeof(FS_Info); i += sizeof(FS_Info))
{
if (entries[i]->size < smallest)
{
smallest = entries[i]->size;
target = entries[i];
}
}
return target;
}
/*
Add entires to the array. If the array is full, use the above function to find the
struct having the smallest file size, and if the current file size is larger, replace it.
*/
void update_fs_info_arr(char *path) // FIXME debug call stack shows that using strncpy here causes segfault
{
static int items_added = 0;
struct stat st;
if (stat(path, &st) == 0)
{
if (items_added < fs_info_arr_size) // if array capacity will not be exceeded
{
strncpy(fs_info_arr[items_added]->name, path, PATH_MAX);
// strlcpy(fs_info_arr[items_added]->name, path, sizeof(fs_info_arr[items_added]->name));
// strncpy(fs_info_arr[items_added]->name, path, sizeof(fs_info_arr[items_added]->name) / sizeof(fs_info_arr[items_added]->name[0]) - 1);
// fs_info_arr[items_added]->name[sizeof(fs_info_arr[items_added]->name) / sizeof(fs_info_arr[items_added]->name[0]) - 1] = 0;
fs_info_arr[items_added]->size = st.st_size;
items_added++;
}
else
// find entry having the smallest size and replace it with the current entry if it is larger
{
FS_Info *smallest = get_smallest_entry(fs_info_arr);
if (st.st_size > smallest->size)
{
strncpy(smallest->name, path, PATH_MAX);
// strlcpy(smallest->name, path, sizeof(smallest->name));
// strncpy(smallest->name, path, sizeof(smallest->name) / sizeof(smallest->name[0]) - 1);
// smallest->name[sizeof(smallest->name) / sizeof(smallest->name[0]) - 1] = 0;
smallest->size = st.st_size;
}
}
}
else
{
printf("Error getting stat for entry %s: %dn", path, stat(path, &st));
}
}
void walk(const char *currDir)
{
DIR *dir = opendir(currDir);
struct dirent *entry;
if (dir == NULL)
{
printf("%s could not be opened", currDir);
return;
}
while ((entry = readdir(dir)) != NULL)
{
// if directory is current dir or parent dir
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
continue;
}
char path_to_entry[PATH_MAX];
snprintf(path_to_entry, sizeof(path_to_entry), "%s/%s", currDir, entry->d_name);
//snprintf(path_to_entry, sizeof(path_to_entry) - 1, "%s/%s", currDir, entry->d_name);
//path_to_entry[sizeof(path_to_entry) - 1] = ' ';
update_fs_info_arr(path_to_entry);
if (entry->d_type == DT_DIR)
{
walk(path_to_entry);
}
}
closedir(dir);
}
int main(int argc, char *argv[])
{
char target_dir[PATH_MAX];
strncpy(target_dir, argv[1], PATH_MAX);
printf("Finding the %zu largest files in: %sn", fs_info_arr_size, target_dir);
// recursively visit all entries in the specified directory
walk(target_dir);
// sort the entries descending by file size
qsort(fs_info_arr, fs_info_arr_size, sizeof(*fs_info_arr), compare);
// output ten largest files found
for (int i = 0; i < fs_info_arr_size; i++)
{
printf("%st%lldn", fs_info_arr[i]->name, fs_info_arr[i]->size);
}
return EXIT_SUCCESS;
}
下面链接的帖子无法初始化strncpy()
复制到的内存,或者涉及错误的size_t num
参数。在后者的情况下,我尝试更改我的代码以匹配下面链接的帖子中描述的模式,但这没有效果。
强度导致分割故障
调用strcpy时出现分段错误
分段错误:11(由strncpy()引起)
为什么使用strncpy时会出现分段错误?
strncpy段错误
strncpy调用的段错误
在c
中使用strny时出现分段错误编辑:我已经按照答案部分的建议进行了修复,并意识到为什么我的程序逻辑有缺陷,但是这个程序仍然导致错误的访问:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
// size of array used to contain filesystem entries
const size_t fs_info_arr_size = 10;
/*
A struct to contain the name of a filesystem entry and its size in bytes.
An array of this type will be used to catalog all filesystem entries for
the directory specified as command line argument.
*/
typedef struct FS_Info
{
char name[PATH_MAX];
long long size;
} FS_Info;
// global pointer to FS_Info array
FS_Info fs_info_arr[fs_info_arr_size];
// used to sort fs_entries array descending in terms of entry size
static int compare(const void *a, const void *b)
{
const struct FS_Info *entryA = (FS_Info *)a;
const struct FS_Info *entryB = (FS_Info *)b;
return entryB->size - entryA->size;
}
/*
Iterates over an array of FS_Info structs and returns a pointer to the struct
having the smallest size member.
*/
FS_Info *get_smallest_entry(FS_Info *entries)
{
long long smallest = entries[0].size;
FS_Info *target;
for (int i = 1; i < fs_info_arr_size; i++)
{
if (entries[i].size < smallest)
{
smallest = entries[i].size;
target = &entries[i];
}
}
return target;
}
/*
Add entires to the array. If the array is full, use the above function to find the
struct having the smallest file size, and if the current file size is larger, replace it.
*/
void update_fs_info_arr(char *path) // FIXME debug call stack shows that using strncpy here causes segfault
{
static int items_added = 0;
struct stat st;
if (stat(path, &st) == 0)
{
if (items_added < fs_info_arr_size) // if array capacity will not be exceeded
{
strncpy(fs_info_arr[items_added].name, path, PATH_MAX);
fs_info_arr[items_added].size = st.st_size;
items_added++;
}
else
// find entry having the smallest size and replace it with the current entry if it is larger
{
FS_Info *smallest = get_smallest_entry(fs_info_arr);
if (st.st_size > smallest->size)
{
strncpy(smallest->name, path, PATH_MAX);
smallest->size = st.st_size;
}
}
}
else
{
printf("Error getting stat for entry %s: %dn", path, stat(path, &st));
}
}
void walk(const char *currDir)
{
DIR *dir = opendir(currDir);
struct dirent *entry;
if (dir == NULL)
{
printf("%s could not be opened", currDir);
return;
}
while ((entry = readdir(dir)) != NULL)
{
// if directory is current dir or parent dir
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
continue;
}
char path_to_entry[PATH_MAX];
snprintf(path_to_entry, sizeof(path_to_entry), "%s/%s", currDir, entry->d_name);
update_fs_info_arr(path_to_entry);
if (entry->d_type == DT_DIR)
{
walk(path_to_entry);
}
}
closedir(dir);
}
int main(int argc, char *argv[])
{
// a char array to hold a filesystem path
char target_dir[PATH_MAX];
strncpy(target_dir, argv[1], PATH_MAX);
printf("Finding the %zu largest files in: %sn", fs_info_arr_size, target_dir);
// recursively visit all entries in the specified directory
walk(target_dir);
// sort the entries descending by file size
qsort(fs_info_arr, fs_info_arr_size, sizeof(*fs_info_arr), compare);
// output ten largest files found
for (int i = 0; i < fs_info_arr_size; i++)
{
printf("%st%lldn", fs_info_arr[i].name, fs_info_arr[i].size);
}
return EXIT_SUCCESS;
}
OP: ">我的程序使用一个静态分配的FS_Info结构数组来存储有关文件系统项的信息。">
代码:
FS_Info *fs_info_arr[fs_info_arr_size];
你正在分配指针,但从来没有分配空间来存储指针可能指向的…
试
FS_Info fs_info_arr[fs_info_arr_size];
,并对代码进行正确的调整,以使用结构体数组(而不是全为NULL的指针数组)
和
static int compare(const void *a, const void *b)
{
const struct FS_Info *entryA = (FS_Info *)a;
const struct FS_Info *entryB = (FS_Info *)b;
return (entryB->size - entryA->size) - (entryA->size - entryB->size);
}
是不必要的复杂。对于降序排序,只需使用
return entryB->size - entryA->size;
(你可以向strncpy()
道歉,因为你不恰当地诽谤了它的声誉。)