我正在尝试创建一个 C 程序,该程序创建一个带有随机整数的 txt 文件,然后
mmap
所述文件和 qsort
它。创建 txt 和映射很顺利,但我不明白为什么 qsort
会破坏它。我猜,这与数据类型有关,但即使在使用它们之后,我也得到或多或少相同的结果。
比较:
int cmp(const void *p1, const void *p2)
{
return (*(const int *)p1 - *(const int *)p2);
}
mmap 和 qsort:
char *addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, myFile, 0);
for (int i = 0; i < size; i++)
printf("%c", addr[i]);
qsort(addr, 20, sizeof(char), cmp);
printf("\n-------------\n");
for (int i = 0; i < size; i++)
printf("%c", addr[i]);
输出示例:
10
19
9
8
18
2
9
6
3
7
15
12
12
14
6
2
4
3
15
13
-------------
296
1
9
93818
1
0
7
15
12
12
14
6
2
4
3
15
13
因此在 txt 中创建了 20 个随机整数并进行映射,没有任何问题。但我猜
qsort
不喜欢它所提供的东西。
我尝试将 mmap
设为 int
,但这会产生其他问题,例如数组中的数字不正确、数字数量不正确以及一些 0(也许我错误地处理了输出)。我不太确定我做错了什么。这是完整的代码,以防需要:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <stdlib.h>
int cmp(const void *p1, const void *p2);
void rand_txt(int size);
int main() {
rand_txt(20);
int myFile = open("rand.txt", O_RDWR);
struct stat myStat = {};
fstat(myFile, &myStat);
off_t size = myStat.st_size;
char *addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, myFile, 0);
for (int i = 0; i < size; i++)
printf("%c", addr[i]);
qsort(addr, 20, sizeof(char), cmp);
printf("\n-------------\n");
for (int i = 0; i < size; i++)
printf("%c", addr[i]);
return 0;
}
int cmp(const void *p1, const void *p2) {
return (*(const int*)p1 - *(const int*)p2);
}
//Function to create a txt with random integers in given size
void rand_txt(int size) {
FILE *fp = fopen("rand.txt", "w");
srand(time(0));
for (int i = 0; i < size; i++)
fprintf(fp, "%d\n", (rand() % size) + 1);
fclose(fp);
}
还有一个快速说明: 数组和指针在实践中的行为方式是否相同(如字符串)?假设我们声明:
int *x = { 10, 20, 30, 40 };
我们可以吗fprint("%d\t", x[i]);
或者这种类型的数组必须声明为 int[] = { 10, 20... };
而不是指针?
(我可以并且会自己测试它,如果没有答案,我会编辑“快速”,直到我能够测试和研究它)
由于多种原因,您无法通过在内存中映射文件并使用比较函数调用
qsort()
来对具有不同大小的数字的文本文件进行排序:
qsort
需要一个所有条目都具有相同大小的数组,这不是文本表示的情况。int
数组,而不是一个文本表示数组int
数组,比较函数也不适合大绝对值,因为减法可能会溢出。要对文本文件进行排序,经典的方法是分配一个
int
数组并从文件中加载值,从文本表示形式转换为 int
值,使用适当的比较函数对 qsort
数组进行排序,并将排序后的数组转换回字符串表示形式。
这是您可以使用的比较功能:
int cmp(const void *p1, const void *p2) {
const int *i1 = p1;
const int *i2 = p2;
return (*i1 > *i2) - (*i1 < *i2);
}
你的代码所做的就是你所写的。没有
qsort
“喜欢”,或功能“思考”。
您逐行编写文本,如下所示。请注意行尾字符:
10\n 19\n 9\n
以下功能
int cmp(const void *p1, const void *p2)
{
return (*(const int*)p1 - *(const int*)p2);
}
获取两个指针,将它们解释为
int*
并比较所指向的两个 int
。类型 int
通常具有 32 位长度。
我会将您的文本写在一行中,看看 cmp
函数会做什么。
p1 p2
| |
v v
10\n1 9\n9\n
比较器将获取字节
10\n1
,将它们解释为int
。
然后它将获取字节9\n9\n
,将它们解释为int
。并比较那些int
。
正如其他人在评论部分指出的那样,
qsort
可能会访问您写入文件的数据。在这种情况下,比较器将比较在 mmap
ed 内存中找到的字节值。
*int x = {10, 20, 30, 40};
打开编译器警告,看看它会告诉你什么。也许尝试打印
x[0], x[1]
。你为什么问这个quickey?您是否陷入了想象中的C
语言?
您应该为字符串设置格式(具有恒定长度和零左填充):
fprintf(fp, "%015d\n", (rand() % size*5) + 1)
然后在
qsort
函数中使用相同的长度+1 大小参数。
您还应该按如下方式更改 u200du200d
cmp
函数,以便它通过 atoi
: 将字符串转换为数字
int cmp(const void *p1, const void *p2)
{
const int i1 = atoi((char*)p1);
const int i2 = atoi((char*)p2);
return (i1 - i2);
}
我建议的代码是:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <stdlib.h>
#include <stdlib.h>
#include <unistd.h>
int cmp(const void *p1, const void *p2)
{
const int i1 = atoi((char*)p1);
const int i2 = atoi((char*)p2);
return (i1 - i2);
}
//Function to create a txt with random integers in given size
void rand_txt(int size)
{
srand(time(0));
FILE *fp = fopen("rand.txt", "w");
for (int i = 0; i < size; i++)
fprintf(fp, "%015d\n", (rand() % size*5) + 1);
fclose(fp);
}
int main()
{
int COUNT=20;
rand_txt(COUNT);
int myFile = open("rand.txt", O_RDWR);
struct stat myStat = {};
fstat(myFile, &myStat);
off_t size = myStat.st_size;
char *addr =(char*) mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, myFile, 0);
close(myFile);
for (int i = 0; i < size; i++)
printf("%c", addr[i]);
qsort(addr, COUNT, 16, cmp);
printf("\n-------------\n");
for (int i = 0; i < size; i++)
printf("%c", addr[i]);
munmap(NULL, size);
return 0;
}