I was trying to figure this out, but now I'm at my wits end.
This is the most relevant link I can find to my problem, but it doesn't help as the struct is a single field, and thus can use strcpy rather than memcpy (for structs with more than one field).
This is the final code changes, the only one I could get the cleanly compile.
#include <stdio.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#define DIR_SIZE 400
#define FILE_SIZE 500
struct _data
{
long int size;
char file[FILE_SIZE + 1];
};
int fill_struct (struct _data **data, char *dir);
void sort_struct (struct _data **data, int count);
// Used for error reporting.
char *program_name = NULL;
void sort_struct (struct _data **data, int count)
{
// Declare variables.
int i = {0};
int j = {0};
struct _data temp = {0};
// Bubble sort struct.
for (i = 0; i < count; i++)
{
for (j = 0; j < count - i; j++)
{
if ((*data[j]).size > (*data[j + 1]).size)
{
memcpy(&temp, (&data)[j], sizeof(struct _data));
memcpy(&data[j], &data[j + 1], sizeof(struct _data));
memcpy(&data[j + 1], &temp, sizeof(struct _data));
}
}
}
}
int main (int argc, char *argv[])
{
// Declare variables.
int count = {0};
struct _data *data = NULL;
// Get program name for error reporting.
program_name = basename(argv[0]);
// Check for correct number of arguments.
if(argc != 2)
{
fprintf(stderr, "usage: %s DIRECTORY\n", program_name);
exit(EXIT_FAILURE);
}
// Get all file info from directory.
count = fill_struct(&data, argv[1]);
// Sort the struct based on size.
sort_struct(&data, count);
// Free allocated memory.
free(data);
// Exit gracefully.
exit(EXIT_SUCCESS);
}
int fill_struct (struct _data **data, char *dir)
{
// Declare variables.
int count = 0;
DIR *dp = NULL;
struct dirent *ep = NULL;
struct _data *temp = NULL;
struct stat file_info = {0};
char file[FILE_SIZE + 1] = {0};
// Open directory for reading.
if((dp = opendir(dir)) == NULL)
{
fprintf(stderr, "%s: fill_struct error: opendir failed (%s) (%s)\n", program_name, dir, strerror(errno));
exit(EXIT_FAILURE);
}
// Loop through all entries.
while((ep = readdir(dp)) != NULL)
{
// Skip everything but files.
if(ep->d_type != DT_REG)
continue;
// Increase count.
count++;
// Build filename path.
strcpy(file, dir);
// Add slash if needed.
if(dir[strlen(dir) - 1] != '/')
strcat(file, "/");
// Add filename.
strcat(file, ep->d_name);
// Get file info.
if(stat(file, &file_info) == -1)
{
fprintf(stderr, "%s: fill_struct error: stat failed (%s) (%s)\n", program_name, file, strerror(errno));
exit(EXIT_FAILURE);
}
// Allocate more memory for additional records.
if((temp = realloc(*data, sizeof(struct _data) * count)) == NULL)
{
fprintf(stderr, "%s: fill_struct error: realloc failed\n", program_name);
free(*data);
exit(EXIT_FAILURE);
}
// Store file data.
strcpy(temp[count - 1].file, file);
temp[count - 1].size = file_info.st_size;
// Change pointer on success.
*data = temp;
}
// Return total count of records.
return(count);
}
Although it compiles cleanly, running it causes a Segmentation fault (core dumped)
Before, I was trying to use (*data)[x]
instead of (&data)[x]
, but I could never get it to compile cleanly.
There are few problems:
if ((*data[j]).size > (*data[j + 1]).size)
{
memcpy(&temp, (&data)[j], sizeof(struct _data));
memcpy(&data[j], &data[j + 1], sizeof(struct _data));
memcpy(&data[j + 1], &temp, sizeof(struct _data));
}
data
is pointer to pointer. data[j]
is a pointer, so &data[j] is go back to pointer to pointer, not just a pointer as memcpy
expect to get.
when you have a pointer to pointer you should first turn it to a pointer by *
prefix then use it as regular pointer. to avoid a dimention error use it inside a parentheses, like: (*data)
It should be:
if ((*data)[j].size > (*data)[j + 1].size)
{
memcpy(&temp, (*data)[j], sizeof(struct _data));
memcpy((*data)[j], (*data)[j + 1], sizeof(struct _data));
memcpy((*data)[j + 1], &temp, sizeof(struct _data));
}
You don't have 2 dimentions array, and you are not changing the allocation. Therefore you shouldn't mess with pointer to pointer. so the function should be declare as:
void sort_struct (struct _data *data, int count)
memcpy
, like:temp = data[j];
data[j] = data[j+1];
data[j+1]= temp;
temp = (*data)[j];
(*data)[j] = (*data)[j+1];
(*data)[j+1]= temp;