具有字母数字文件名的qsort动态2d字符数组-C程序
我是新来的,所以这是我的第一篇帖子。为了解决这个问题,我已经苦苦挣扎了两周。我试图打开一个目录,捕获并存储找到的文件名,按升序排序,然后打印结果。我的问题是qsort导致我的程序完全崩溃,或者qsort根本不对数组排序,因为文件是字母数字的。我甚至尝试通过一个存储的文件名循环输出每个字符,只是想看看是否最终可以尝试比较两个数组位置之间的字符进行排序。但我注意到,它似乎无法看到或识别字母数字文件名中的数字(例如:“f1.jpg”将只打印“f”,一个空格,然后是“j”,仅此而已。我应该注意,我无法更改文件名,因为我事先不知道文件名或文件总数。我正在尝试使其成为动态的。以下是我遇到问题的主要代码,因为它在“qsort”关键字处崩溃:具有字母数字文件名的qsort动态2d字符数组-C程序,c,sorting,multidimensional-array,alphanumeric,qsort,C,Sorting,Multidimensional Array,Alphanumeric,Qsort,我是新来的,所以这是我的第一篇帖子。为了解决这个问题,我已经苦苦挣扎了两周。我试图打开一个目录,捕获并存储找到的文件名,按升序排序,然后打印结果。我的问题是qsort导致我的程序完全崩溃,或者qsort根本不对数组排序,因为文件是字母数字的。我甚至尝试通过一个存储的文件名循环输出每个字符,只是想看看是否最终可以尝试比较两个数组位置之间的字符进行排序。但我注意到,它似乎无法看到或识别字母数字文件名中的数字(例如:“f1.jpg”将只打印“f”,一个空格,然后是“j”,仅此而已。我应该注意,我无法更
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <conio.h>
#include <ctype.h>
#include <time.h>
#include <dirent.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int compare(const void *a, const void *b);
void readInFilenames();
int main
{
readInFilenames();
system("pause");
}
int compare(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
}
void readInFilenames()
{
char cwd[1024];
DIR *dir = NULL;
struct dirent *pent = NULL;
struct stat info;
char file_path[50] = "files/";
int total_files = 0;
int file_size;
// Change directory to file location
chdir(file_path);
if((getcwd(cwd, sizeof(cwd))) != NULL)
{
printf("Current Directory: %s\n", cwd);
}
// Open directory and count the total number of files found
dir = opendir(cwd);
if(dir != NULL)
{
while((pent = readdir(dir)) != NULL)
{
if(stat(pent->d_name, &info))
{
printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
}
else
{
if(S_ISREG(info.st_mode))
{
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
total_files++;
file_size = sizeof(pent->d_name);
}
}
}
}
printf("# of files found: %d\n", total_files);
rewinddir(dir); //reset pointer back to beginning of file directory
// Create character array to store file names;
char *filenames_arr[total_files][file_size];
int size = sizeof(filenames_arr)/sizeof(filenames_arr[total_files]);
total_files = 0; //reset file counter back to 0;
// Read and store file names in the character array
while((pent = readdir(dir)) != NULL)
{
if(stat(pent->d_name, &info))
{
printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
}
else
{
if(S_ISREG(info.st_mode))
{
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
strcpy(filenames_arr[total_files], pent->d_name);
//printf("%s\n", filenames_arr[i]);
total_files++;
}
}
}
}
closedir(dir);
// Print original array contents
printf("Original List of Files\n");
printf("----------------------\n");
for(int i = 0; i < total_files; i++)
{
printf("%s\n", filenames_arr[i]);
}
// Sort array in ascending order
qsort(filenames_arr, total_files, size, compare);
//qsort(filenames_arr, total_files, sizeof(filenames_arr[0]), (char (*)(const void*, const void*))strcmp);
// Print organized array contents
printf("Sorted List of Files\n");
printf("----------------------\n");
for(int i = 0; i < total_files; i++)
{
printf("%s\n", filenames_arr[i]);
}
printf("\nFinished!\n");
}
}
列表应该打印:f0.dat,f1.dat,f2.dat,f3.dat,…,f20.dat。但是它会打印:f0.dat,f1.dat,f10.dat,f11.dat,…,f9.dat。OP有固定的代码,通过启用警告和使用建议来处理“带文件名的qsort动态2d字符数组” 然而,code仍在与strcmp()进行比较,strcmp()只将数字视为字符,而不以数字形式实现f1.dat、f2.dat、f3.dat、…、f20.dat的顺序
下面是一个比较函数,它查找数字以调用数字子字符串的替代比较。OP可以对此比较进行更改,以满足详细的编码目标
int AdamsOrder(const char *s1, const char *s2) {
// Compare as `unsigned char` as that is `strcmp()` behavior. C11 7.24.1 3
const unsigned char *us1 = (const unsigned char *) s1;
const unsigned char *us2 = (const unsigned char *) s2;
while (*us1 && *us2) {
if (isdigit(*us1) && isdigit(*us2)) {
char *end; // dummy
unsigned long long l1 = strtoull(us1, &end, 10); // Parse for a number
unsigned long long l2 = strtoull(us2, &end, 10);
if (l1 > l2) return 1;
if (l1 < l2) return -1;
// Continue on treating as text. OP needs to decide how to handle ties: "0001" vs "1"
}
if (*us1 > *us2) return 1;
if (*us1 < *us2) return -1;
us1++;
us2++;
}
// At this point, at least one string ended (i.e. points to '\0').
// The return statement below will behave as follows:
// If a string ended, *us1/2 will be 0. Let an unfinished one be X > 0.
// First string ended : ( 0 > X ) - ( 0 < X ) = false - true = 0 - 1 = -1
// Second string ended: ( X > 0 ) - ( X < 0 ) = true - false = 1 - 0 = 1
// Both strings ended : ( 0 > 0 ) - ( 0 < 0 ) = false - false = 0 - 0 = 0
return (*us1 > *us2) - (*us1 < *us2);
}
intadamsorder(常量字符*s1,常量字符*s2){
//将'unsigned char'与'strcmp()`behavior.C11 7.24.1 3进行比较
常量无符号字符*us1=(常量无符号字符*)s1;
常量无符号字符*us2=(常量无符号字符*)s2;
而(*us1&&*us2){
if(isdigit(*us1)和&isdigit(*us2)){
char*end;//虚拟
unsigned long l1=strtoull(us1,&end,10);//解析一个数字
无符号长l2=strtoull(us2和end,10);
如果(l1>l2)返回1;
如果(l1*us2)返回1;
如果(*us1<*us2)返回-1;
us1++;
us2++;
}
//此时,至少有一个字符串结束(即指向“\0”)。
//下面的return语句的行为如下:
//如果字符串结束,*us1/2将为0。让未完成的字符串为X>0。
//第一个字符串结束:(0>X)-(00)-(X<0)=真-假=1-0=1
//两个字符串都以:(0>0)-(0<0)=false-false=0-0=0结尾
返回(*us1>*us2)-(*us1<*us2);
}
filenames\u arr
是指向字符的指针的数组文件大小的“数组总文件数”
。数组的每个元素都是指向字符的指针的“数组文件大小的”
。该元素的两个地址被传递到qsort()
。它们不是(char**)
类型“指向数组的指针<代码>文件大小
指向字符的指针”。键入不匹配。strcpy(文件名\u arr[总文件],pent->d\u名称);
由于类型不匹配,应生成警告。节省时间:启用所有编译器警告。是否可以使用具有char*filename等成员的struct filedata重新定义文件名\u arr?然后可以创建struct filedata fn\u data[total\u files]您仍然需要malloc每个fn_data.filename的长度为file_大小。我通常以这种方式调用qsort,因为所有内容都是线性打包在一起的,以便与.qsort(fn_数据、total_文件、sizeof(struct filedata)、compare)一起使用;compare函数可以查看它获得的传递数据,并根据需要遵循任何指针,但完成后,外部qsort调用将重新组织每个数据单元,以保持数据的压缩linearly@chux:您的第二条评论是对的。我不知道如何解决strcpy不匹配的警告。我使用了@Snohdo评论建议并重新组织了我的代码,这有助于解决警告和错误。根据建议,qsort
不再使我的程序崩溃,因为@chux first suggestion关于不匹配的指针数组是正确的。但是,它仍然没有对文件进行排序。我将更新我的原始帖子,以显示编辑和结果lts.@N.Adams提示:不要有条件地使用int file\u size=sizeof(pent->d\u name)
,而是使用int file\u size=sizeof(pent->d\u name)
。这样可以避免使用char*filename\arr[total\u files][file\u size]
发生在文件大小中的未初始化值
我尝试了该代码,并将比较
函数中的strcmp
替换为AdamsOrder
。它没有崩溃,但陷入了无限循环。我想知道它在代码中的何处停止并挂起。也许我会尝试使用5个文件,看看是否有问题再次发生,或者如果它完成了排序过程。谢谢你的帮助!效果非常好。我也接受了答案:)@chux这帮了大忙(我添加了处理领带的代码,但在其他方面使用了几乎相同的代码)。我在不太明显的最后一个返回语句上添加了一些解释。如果您能验证我的注释并在它们错误时对其进行修改,那就太好了。@TimMeyer Edit是可以的。请注意,(a>b)-(b
是健壮的fcmp()
函数中常用的习惯用法。
typedef struct{
char *filename;
}filedata;
int compare(const void *a, const void *b);
void readInFilenames();
int main(void){
readInFilenames();
system("pause");
}
int compare (const void *a, const void *b ) {
filedata *ia = (filedata *)a;
filedata *ib = (filedata *)b;
return strcmp(ia->filename, ib->filename);
}
readInFilenames(){
.
.
.
printf("# of files found: %d\n", total_files);
rewinddir(dir);
filedata fn_data[total_files];
total_files = 0;
printf("Original Array: \n");
while((pent = readdir(dir)) != NULL)
{
.
.
.
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
fn_data[total_files].filename = malloc(file_size + 1);
strcpy(fn_data[total_files].filename, pent->d_name);
printf("%s\n", fn_data[total_files].filename);
total_files++;
}
}
closedir(dir);
printf("\n");
qsort(fn_data, total_files, sizeof(filedata), compare);
printf("Sorted Array:\n");
for(int i = 0; i < total_files; i++)
printf("%s\n", fn_data[i].filename);
printf("Finished!\n");
}
int AdamsOrder(const char *s1, const char *s2) {
// Compare as `unsigned char` as that is `strcmp()` behavior. C11 7.24.1 3
const unsigned char *us1 = (const unsigned char *) s1;
const unsigned char *us2 = (const unsigned char *) s2;
while (*us1 && *us2) {
if (isdigit(*us1) && isdigit(*us2)) {
char *end; // dummy
unsigned long long l1 = strtoull(us1, &end, 10); // Parse for a number
unsigned long long l2 = strtoull(us2, &end, 10);
if (l1 > l2) return 1;
if (l1 < l2) return -1;
// Continue on treating as text. OP needs to decide how to handle ties: "0001" vs "1"
}
if (*us1 > *us2) return 1;
if (*us1 < *us2) return -1;
us1++;
us2++;
}
// At this point, at least one string ended (i.e. points to '\0').
// The return statement below will behave as follows:
// If a string ended, *us1/2 will be 0. Let an unfinished one be X > 0.
// First string ended : ( 0 > X ) - ( 0 < X ) = false - true = 0 - 1 = -1
// Second string ended: ( X > 0 ) - ( X < 0 ) = true - false = 1 - 0 = 1
// Both strings ended : ( 0 > 0 ) - ( 0 < 0 ) = false - false = 0 - 0 = 0
return (*us1 > *us2) - (*us1 < *us2);
}