[英]Segfault when using memmove()
I am working on a program written in C that recursively walks a given directory in order to print out the Nth largest files and their sizes in bytes.我正在开发一个用 C 编写的程序,它递归地遍历给定的目录,以便打印出第 N 个最大的文件及其大小(以字节为单位)。 I am using two arrays to account for the filesystem entry names and filesystem entry sizes respectively.
我使用两个数组分别说明文件系统条目名称和文件系统条目大小。
EDIT: I have updated my program to implement the suggestions shared in the comment section.编辑:我已经更新了我的程序以实施评论部分中共享的建议。 I have also provided a full program instead of a 'bunch of snippets' as suggested in a comment, but this is becoming quite a bit of code.
我还提供了一个完整的程序,而不是评论中建议的“一堆片段”,但这已经变成了相当多的代码。 My focus now is on correctly implementing a swap operation within my
iSort
function.我现在的重点是在我的
iSort
函数中正确实现交换操作。
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
// number of files to display size information for
const int N = 10;
// a struct used to hold filesystem entry names and corresponding sizes in bytes
struct info {
char name[1024];
int size;
};
/* A simple implementation of insertion sort that will operate upon
an array of info structs, sorting them by their member size in
ascending order */
void iSort(struct info *fs_info[], int size, int info_size)
{
int i, j, key;
for (i = 1; i < size; i++)
{
key = fs_info[i]->size;
j = i - 1;
while (j >= 0 && fs_info[j]->size > key)
{
printf("info_size: %d\n", info_size);
// TODO complete a swap operation
memmove(fs_info[j + 1], fs_info[j], info_size);
j = j - 1;
}
fs_info[j + 1]->size = key;
}
}
void get_size(char *path, struct info fs_info[N], int info_size)
{
static int items_added = 0;
static int max_size = 0;
struct stat st;
if (stat(path, &st) == 0)
{
if (items_added < N) // if array capacity will not be exceeded
{
strcpy(fs_info[items_added].name, path);
fs_info[items_added].size = st.st_size;
if (st.st_size > max_size)
max_size = st.st_size;
items_added++;
}
else
{
// do a comparison to determine where to insert
// sort first
iSort(&fs_info, 10, info_size); // this function call results in a seqfault
}
}
else
{
printf("Error getting stat for entry %s: %d\n", path, stat(path, &st));
}
}
void walk(const char *currDir, struct info fs_info[N], int info_size)
{
DIR *dir = opendir(currDir);
struct dirent *entry;
if (dir == NULL)
{
// directory could not be opened
return;
}
while ((entry = readdir(dir)) != NULL)
{
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
// if directory is current dir or parent dir
continue;
}
char path_to_entry[1024];
snprintf(path_to_entry, sizeof(path_to_entry), "%s/%s", currDir, entry->d_name);
// use path_to_entry to call stats on the entry
get_size(path_to_entry, fs_info, info_size);
if (entry->d_type == DT_DIR)
{
// recursively visit subdirectories
walk(path_to_entry, fs_info, info_size);
}
}
closedir(dir);
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: %s <target directory>\n", argv[0]);
}
const char *target_dir = argv[1];
struct info fs_entries[N];
const int info_size = sizeof(struct info);
for (int i = 0; i < N; i++)
{
strcpy(fs_entries[i].name, "");
fs_entries[i].size = 0;
}
printf("Finding %d largest files in: %s\n", N, target_dir);
walk(target_dir, fs_entries, info_size);
for (int i = 0; i < N; i++)
{
printf("%s : %d\n", fs_entries[i].name, fs_entries[i].size);
}
return 0;
}
Currently, the memmove()
invocation in iSot()
results in a EXC_BAD_ACCESS
error, I am working on improving this function now.目前,
iSot()
中的memmove()
调用导致EXC_BAD_ACCESS
错误,我正在努力改进此功能。 Any suggestions in the interim are appreciated.在此期间提出任何建议,我们将不胜感激。 Thanks also to those who commented on this question earlier.
也感谢那些早些时候评论过这个问题的人。
You don't need to pass the address of fs_info
to iSort()
function.您不需要将
fs_info
的地址传递给iSort()
函数。 fs_info
is a pointer to first element of fs_entries
array, which is enough to sort the array if the size of array is known. fs_info
是指向fs_entries
数组第一个元素的指针,如果数组的大小已知,它足以对数组进行排序。 Also, you don't need to pass the size of element of array to iSort()
.此外,您不需要将数组元素的大小传递给
iSort()
。
iSort()
function implementation: iSort()
函数实现:
void iSort (struct info *fs_info, int size) {
int key, j;
struct info x;
for (int i = 1; i < size; ++i) {
key = fs_info[i].size;
x = fs_info[i];
j = i - 1;
while(j >= 0 && fs_info[j].size > key) {
fs_info[j + 1] = fs_info[j];
j--;
}
fs_info[j + 1] = x;
}
}
Call it like this:像这样称呼它:
iSort(fs_info, N);
There is a lot of scope of improvement in your code, like, it would be good to have array of pointers to struct info
instead of array of struct info
, so that, during sort simply swapping the pointers required instead of swapping whole structure.您的代码有很多改进的余地,例如,最好使用指向
struct info
的指针数组而不是struct info
info 的数组,这样,在排序过程中只需交换所需的指针而不是交换整个结构。 Leaving it up to you to identify the improvements and implement them.由您来确定改进并实施它们。
This is not so much an answer as it is an example of how one might code this with a bit less fiddling about with every bit/byte.这与其说是一个答案,不如说是一个示例,说明人们如何用更少的每一位/字节来编写代码。
I don't run a flavour of UNIX, so this offering is untested and may contain typos and even bugs.我不运行 UNIX 风格,因此此产品未经测试,可能包含拼写错误甚至错误。 I hope not.
我希望不是。
#include <stdio.h> // From 'generic' to 'specific'
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
const int N = 10;
// Global array holding names and sizes
struct {
char name[ MAX_PATH ];
size_t size;
} biggies[ N ], wrk; // and a working buffer.
/* "Global" is bad for large projects.
* In this 'utility' program, global saves a LOT of typing/reading.
* Seek clarity, not conformity,
*
* "wrk" is used to buffer ALL paths encountered.
* Notice that each recursion is an EXTENSION of its parent.
* ONE working buffer to deal with.
*/
void walk() {
size_t len = strlen( wrk.name ); // The path so far...
DIR *dir;
if( ( dir = opendir( wrk.name ) ) == NULL )
return;
wrk.name[ len++ ] = '/'; // append a slash ahead of strcpy() below
struct dirent *entry;
while( ( entry = readdir( dir ) ) != NULL ) {
if( strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 )
continue;
// Notice how each 'local' name is written to "the right spot" in one buffer
strcpy( wrk.name + len, entry->d_name );
if( entry->d_type == DT_DIR ) // directory, so recursion...
walk();
else {
struct stat st;
if( stat( wrk.name, &st ) != 0 ) {
fprintf( stderr, "Error stat'ing '%s'\n", path );
exit( EXIT_FAILURE );
}
// Add this info to working buffer.
wrk.size = st.st_size;
// Find where to 'insert' this (if it is larger than descending ordered list
for( int i = 0; i < N && biggies[i].size > wrk.size; i++ ) {} // loop
if( i < N ) {
// Slide smaller ones down (don't go out of bounds)
memmove( biggies[i + 1], biggies[i], (N-i-1) * sizeof biggies[0] );
// Copy this one in place.
memcpy( biggies[i], &wrk, sizeof biggies[0] );
}
}
}
closedir(dir);
}
int main( int argc, char *argv[]) {
char *target_dir = argv[1]; // This is okay, so far...
if( argc != 2 ) {
printf( "Usage: %s <target directory>\n", argv[0] );
puts( "Using current directory..." );
target_dir = ".";
}
strcpy( wrk.name, target_dir );
printf( "Finding %d largest files in: %s\n", N, wrk.name );
walk();
for( size_t i = 0; i < N && biggies[i].size != 0; i++ )
printf( "%s : %d\n", biggies[i].name, biggies[i].size);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.