带有memcpy问题的C置换

The*_*net 1 c unix memcpy

给定一个任何类型的数组(在本例中为整数)和一个Map,它告诉我们应该在数组中交换哪些索引.我试图进行干净的交换,但遇到了我使用memcpy的问题.

这是我到目前为止:

目标:给定[1,3,-1,2]的数据数组和[[0,3],[3,2],[2,1],[1,0]]的映射,一个干净的排列将是[3,-1,2,1].

我当前的实现:0 3 -1 2 ...我想我在某个地方有一个错误的错误.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAP_SIZE 4

typedef struct MapEntry {
    int indexFrom;
    int indexTo;
} MapEntry;

typedef MapEntry * Map;

int permute(void *data, int nblobs, int szblob, const Map map);

void build_map(Map);
void build_data(int *);
int is_map_valid(Map);
void print_map(Map);
int is_valid(Map);

int map_comparator(const void * a, const void * b);

int main(int argc, char const *argv[])
{
    int nblobs, * data, i;
    size_t szblob;
    Map map = (Map)malloc(sizeof(Map));
    data = (int *) malloc(sizeof(int) * 4);

    build_map(map);

    data[0] = 1;
    data[1] = 3;
    data[2] = -1;
    data[3] = 2;

    nblobs = 4;
    szblob = sizeof(int);

    if (!permute(data, nblobs, szblob, map)) {
        printf("Invalid Map\n");
        return 0;
    }

    i = 0;
    for (i = 0; i < szblob; ++i) {
        printf("%d ", data[i]);
    }

    return 0;
}

void print_map(Map map){
    int i;
    for (i = 0; i < MAP_SIZE; ++i) {
        printf("[%d - %d]\n", map[i].indexFrom, map[i].indexTo);
    }
}

int map_comparator(const void *a, const void *b)
{
    const MapEntry *s1 = a;
    const MapEntry *s2 = b;
    if (s2->indexFrom != s1->indexFrom) {
        return s1->indexFrom - s2->indexFrom;
    } else {
        return s1->indexTo - s2->indexTo;
    }
}

int is_map_valid(Map map) {
    int i,j;
    for (i = 1; i < MAP_SIZE; ++i){
        j = i - 1;
        if (map[j].indexFrom == map[i].indexFrom)
            return 0;
        if (map[j].indexTo == map[i].indexTo)
            return 0;
    }
    return 1;
}

int is_valid(Map map) {
    qsort(map, MAP_SIZE, sizeof(MapEntry), map_comparator);
    if (!is_map_valid(map)) return 0;
    return 1;
}


int permute(void *data, int nblobs, int szblob, const Map map){
    int i, tmpFrom, tmpTo;
    void * a = (void *)malloc(szblob);
    char *p = data;

    /* check if map has duplicate keys */
    /* sort the list, then check whether or not the map is valid */
    if (!is_valid(map)) return 0;
    /* where issues occur */

    for (i = 0; i < nblobs; ++i){

        tmpFrom = map[i].indexFrom;

        tmpTo = map[i].indexTo;

        memcpy(a, &p[tmpFrom*szblob], szblob);

        memcpy(&p[tmpFrom*szblob], &p[tmpTo*szblob], szblob);

        memcpy(&p[tmpTo*szblob], a, szblob);

    }

    return 1;

}
/* build mapping */
void build_map(Map map){
    map[0].indexFrom = 0;
    map[0].indexTo = 3;
    map[1].indexFrom = 3;
    map[1].indexTo = 2;
    map[2].indexFrom = 2;
    map[2].indexTo = 1;
    map[3].indexFrom = 1;
    map[3].indexTo = 0;

}
Run Code Online (Sandbox Code Playgroud)

小智 5

你是默认启用和非标准GCC延伸的受害者允许 指针算术上的指针中的孔隙和指针通过处理空隙的或函数为1.此扩展的大小的功能可以通过指定一个被禁用C标准,比方说,C99,使用-std选项 - 例如,-std=c99(详见gcc手册页).或者,您可以通过指定-Wpointer-arith选项要求gcc为此类情况发出警告.

回到问题,考虑一下你写的时候会发生什么&data[tmpFrom].data获取指向的地址,然后将tmpFrom字节添加到该地址.你想要的是添加tmpFrom * sizeof(int)字节.要实现这一点,您必须根据类型的值tmpFromint类型的大小手动计算所需的字节数,或者data将指针声明为指向类型的指针int.第二种是首选的方法,但如果你真的希望你的函数支持任意数据类型,那么你必须回到更难的第一种方法.

下面是clang生成的警告列表(诊断通常会更好):

$ clang -Wall -pedantic -o test ./test.c
./test.c:109:18: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(a, &data[tmpFrom], szblob);
                ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:36: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                                   ^
./test.c:109:13: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(a, &data[tmpFrom], szblob);
                ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:36: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                                   ^
./test.c:109:18: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(a, &data[tmpFrom], szblob);
                ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:56:33: note: expanded from macro 'memcpy'
   : __inline_memcpy_chk (dest, src, len))
                                ^
./test.c:109:13: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(a, &data[tmpFrom], szblob);
                ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:56:33: note: expanded from macro 'memcpy'
   : __inline_memcpy_chk (dest, src, len))
                                ^
./test.c:111:15: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:54:21: note: expanded from macro 'memcpy'
  ((__darwin_obsz0 (dest) != (size_t) -1)                               \
                    ^
/usr/include/secure/_common.h:38:55: note: expanded from macro '__darwin_obsz0'
#define __darwin_obsz0(object) __builtin_object_size (object, 0)
                                                      ^~~~~~
./test.c:111:10: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:54:21: note: expanded from macro 'memcpy'
  ((__darwin_obsz0 (dest) != (size_t) -1)                               \
                    ^
/usr/include/secure/_common.h:38:55: note: expanded from macro '__darwin_obsz0'
#define __darwin_obsz0(object) __builtin_object_size (object, 0)
                                                      ^~~~~~
./test.c:111:15: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:30: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                             ^
./test.c:111:10: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:30: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                             ^
./test.c:111:31: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:36: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                                   ^
./test.c:111:26: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:36: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                                   ^
./test.c:111:15: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:62: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                                                             ^
/usr/include/secure/_common.h:38:55: note: expanded from macro '__darwin_obsz0'
#define __darwin_obsz0(object) __builtin_object_size (object, 0)
                                                      ^~~~~~
./test.c:111:10: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:62: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                                                             ^
/usr/include/secure/_common.h:38:55: note: expanded from macro '__darwin_obsz0'
#define __darwin_obsz0(object) __builtin_object_size (object, 0)
                                                      ^~~~~~
./test.c:111:15: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:56:27: note: expanded from macro 'memcpy'
   : __inline_memcpy_chk (dest, src, len))
                          ^
./test.c:111:10: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:56:27: note: expanded from macro 'memcpy'
   : __inline_memcpy_chk (dest, src, len))
                          ^
./test.c:111:31: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:56:33: note: expanded from macro 'memcpy'
   : __inline_memcpy_chk (dest, src, len))
                                ^
./test.c:111:26: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(&data[tmpFrom], &data[tmpTo], szblob);
                ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:56:33: note: expanded from macro 'memcpy'
   : __inline_memcpy_chk (dest, src, len))
                                ^
./test.c:113:15: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(&data[tmpTo], a, szblob);
                ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:54:21: note: expanded from macro 'memcpy'
  ((__darwin_obsz0 (dest) != (size_t) -1)                               \
                    ^
/usr/include/secure/_common.h:38:55: note: expanded from macro '__darwin_obsz0'
#define __darwin_obsz0(object) __builtin_object_size (object, 0)
                                                      ^~~~~~
./test.c:113:10: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(&data[tmpTo], a, szblob);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:54:21: note: expanded from macro 'memcpy'
  ((__darwin_obsz0 (dest) != (size_t) -1)                               \
                    ^
/usr/include/secure/_common.h:38:55: note: expanded from macro '__darwin_obsz0'
#define __darwin_obsz0(object) __builtin_object_size (object, 0)
                                                      ^~~~~~
./test.c:113:15: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(&data[tmpTo], a, szblob);
                ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:30: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                             ^
./test.c:113:10: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(&data[tmpTo], a, szblob);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:30: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                             ^
./test.c:113:15: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(&data[tmpTo], a, szblob);
                ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:62: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                                                             ^
/usr/include/secure/_common.h:38:55: note: expanded from macro '__darwin_obsz0'
#define __darwin_obsz0(object) __builtin_object_size (object, 0)
                                                      ^~~~~~
./test.c:113:10: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(&data[tmpTo], a, szblob);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:55:62: note: expanded from macro 'memcpy'
   ? __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))     \
                                                             ^
/usr/include/secure/_common.h:38:55: note: expanded from macro '__darwin_obsz0'
#define __darwin_obsz0(object) __builtin_object_size (object, 0)
                                                      ^~~~~~
./test.c:113:15: warning: subscript of a pointer to void is a GNU extension [-pedantic,-Wpointer-arith]
                memcpy(&data[tmpTo], a, szblob);
                ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:56:27: note: expanded from macro 'memcpy'
   : __inline_memcpy_chk (dest, src, len))
                          ^
./test.c:113:10: warning: ISO C forbids taking the address of an expression of type 'void' [-pedantic]
                memcpy(&data[tmpTo], a, szblob);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:56:27: note: expanded from macro 'memcpy'
   : __inline_memcpy_chk (dest, src, len))
                          ^
24 warnings generated.
Run Code Online (Sandbox Code Playgroud)

一旦上述警告得到修复,它就应该有效.但是,还有两个问题......

第一个问题是错误的预期结果.应该3, -1, 1, 2而不是3, -1, 2, 1.映射应该像这样排序:

0,3
1,0
2,1
3,2
Run Code Online (Sandbox Code Playgroud)

排列应分四步完成:

1) 2, 3, -1, 1
2) 3, 2, -1, 1
3) 3, -1, 2, 1
4) 3, -1, 1, 2
Run Code Online (Sandbox Code Playgroud)

第二个问题是不正确的排序.通过执行两种排序,首先是"from"值,第二次是"to"值,最终会得到一个仅按"to"排序的映射(您调用的最后一种排序).应该做的是使用谓词的单一排序,该谓词比较每个元素的"从"和"到".例如:

int map_comparator(const void *a, const void *b)
{
    const MapEntry *s1 = a;
    const MapEntry *s2 = b;
    if (*s2->indexFrom != *s1->indexFrom) {
        return *s1->indexFrom - *s2->indexFrom;
    } else {
        return *s1->indexTo - *s2->indexTo;
    }
}
Run Code Online (Sandbox Code Playgroud)

一旦上述问题得到解决,一切都会奏效.除此之外,您的代码中只有少数建议可能会有所帮助:

  1. 您正在使用太多动态分配.考虑重新思考如何做到这一点.例如,我认为不需要动态分配结构indexFromindexTo字段MapEntry.
  2. 你有不必要的演员阵容void *.例如:void * a = (void *)malloc(szblob);应该只是void *a = malloc(szblob);.
  3. 不必要的强制void *类型转换为其他指针类型int *.这在C中是不必要的,其中void *指针可以隐式转换为其他类型的指针.但是,对于C++来说并非如此.
  4. typedef除非目标是创建一个opaque类型(在您的情况下不是这样),否则不要构造.打字struct可能看起来像很多打字,但它为那些阅读你的代码的C开发人员提供了关于类型的一个很好的提示.例如,请参阅Linux内核编码样式的第5章,以获得很好的解释.

我鼓励您自己修改代码,但这里是您的代码,只需进行最少的必要更改即可使其工作,供您参考:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAP_SIZE 4

typedef struct MapEntry {
    int * indexFrom;
    int * indexTo;
} MapEntry;

typedef MapEntry * Map;

int permute(void *data, int nblobs, int szblob, const Map map);

void build_map(Map);
void build_data(int *);
int is_map_valid(Map);
void print_map(Map);
int is_valid(Map);

int map_comparator(const void * a, const void * b);

int main(int argc, char const *argv[])
{
    int nblobs, * data, i;
    size_t szblob;
    Map map = (Map)malloc(sizeof(Map));
    data = (int *) malloc(sizeof(int) * 4);

    build_map(map);

    data[0] = 1;
    data[1] = 3;
    data[2] = -1;
    data[3] = 2;

    nblobs = 4;
    szblob = sizeof(int);

    if (!permute(data, nblobs, szblob, map)) {
        printf("Invalid Map\n");
        return 0;
    }

    i = 0;
    for (i = 0; i < szblob; ++i) {
        printf("%d ", data[i]);
    }

    return 0;
}

void print_map(Map map){
    int i;
    for (i = 0; i < MAP_SIZE; ++i) {
        printf("[%d - %d]\n", *map[i].indexFrom, *map[i].indexTo);
    }
}

int map_comparator(const void *a, const void *b)
{
    const MapEntry *s1 = a;
    const MapEntry *s2 = b;
    if (*s2->indexFrom != *s1->indexFrom) {
        return *s1->indexFrom - *s2->indexFrom;
    } else {
        return *s1->indexTo - *s2->indexTo;
    }
}

int is_map_valid(Map map) {
    int i,j;
    for (i = 1; i < MAP_SIZE; ++i){
        j = i - 1;
        if (*map[j].indexFrom == *map[i].indexFrom)
            return 0;
        if (*map[j].indexTo == *map[i].indexTo)
            return 0;
    }
    return 1;
}

int is_valid(Map map) {
    qsort(map, MAP_SIZE, sizeof(MapEntry), map_comparator);
    if (!is_map_valid(map)) return 0;
    return 1;
}


int permute(void *data, int nblobs, int szblob, const Map map){
    int i, tmpFrom, tmpTo;
    void * a = (void *)malloc(szblob);
    char *p = data;

    /* check if map has duplicate keys */
    /* sort the list, then check whether or not the map is valid */
    if (!is_valid(map)) return 0;
    /* where issues occur */

    for (i = 0; i < nblobs; ++i){

        tmpFrom = *map[i].indexFrom;

        tmpTo = *map[i].indexTo;

        memcpy(a, &p[tmpFrom*szblob], szblob);

        memcpy(&p[tmpFrom*szblob], &p[tmpTo*szblob], szblob);

        memcpy(&p[tmpTo*szblob], a, szblob);

    }

    return 1;

}
/* build mapping */
void build_map(Map map){
    int i;
    for (i = 0; i < MAP_SIZE; ++i) {
        map[i].indexFrom = (int *)malloc(sizeof(int));
        map[i].indexTo = (int *)malloc(sizeof(int));
    }

    *map[0].indexFrom = 0;
    *map[0].indexTo = 3;

    *map[1].indexFrom = 3;
    *map[1].indexTo = 2;

    *map[2].indexFrom = 2;
    *map[2].indexTo = 1;

    *map[3].indexFrom = 1;
    *map[3].indexTo = 0;

}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.保持温暖,祝你好运!