在 C 中使用随机整数对 mmaped 文件进行排序

问题描述 投票:0回答:3

我正在尝试创建一个 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... };
而不是指针? (我可以并且会自己测试它,如果没有答案,我会编辑“快速”,直到我能够测试和研究它)

c mmap qsort
3个回答
0
投票

由于多种原因,您无法通过在内存中映射文件并使用比较函数调用

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);
}

0
投票

你的代码所做的就是你所写的。没有

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
语言?


0
投票

您应该为字符串设置格式(具有恒定长度和零左填充):

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;
}
© www.soinside.com 2019 - 2024. All rights reserved.