简体   繁体   English

使用 memmove() 时的段错误

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM