使用指针的通用冒泡排序程序

时间:2014-03-01 17:45:53

标签: c arrays pointers char

从我以前的问题:

Segmentation Fault in Bubble Sort

我解决了问题,我得到了以下代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void bubble_sort (void* base, 
                  size_t num, 
                  size_t width,
                  int (*compar)(const void*,const void*)){
    int i,j,k;
    unsigned char *ptr = base;
    unsigned char tmp[256];

    if(num < 2 || width == 0)
        return;

    for(i = num-1; i >= 0; i--)
    {
        for(j = 1; j <= i; j++)
        {
            k = compar((void*)(ptr + width * (j-1)), (void*)(ptr + width * j));
            if(k > 0)
            {
                memcpy(tmp, ptr + width*(j-1), width);
                memcpy(ptr + width*(j-1), ptr + width*j, width);
                memcpy(ptr + width * j, tmp, width);
            }
        }
    }
}

int compare_int(const void *a, const void *b)
{
    int *c = (int *)a;
    int *d = (int *)b;
    return *c - *d;
}

int compare_string(const void *a, const void *b)
{
    const char *c = (char *)a;
    const char *d = (char *)b;
    return strcmp(c, d);
}

现在这完全适用于:

  1. Int,Long等像int a[] = {1, 3, 4, 52, 2, 3};
  2. 这样的数组
  3. char数组,如char a[5][20] = { "jhsa", "asndb", "drtfe", "nhurh", "bvhr"};
  4. 但我想用char *数组实现它,如:

    1. char *a[] = { "jhsa", "asndb", "drtfe", "nhurh", "bvhr"}
    2. 尝试了一下并遇到了分段故障 所以需要一些帮助。

3 个答案:

答案 0 :(得分:3)

您将变量'a'声明为char指针(字符串)。但你拥有的是一系列字符串。

因此'a'应该是这样的

char *a[] = { "jhsa", "asndb", "drtfe", "nhurh", "bvhr"};

此外,您应该为变量赋予更有意义的名称。在这种情况下,字符串或单词会更清晰。

答案 1 :(得分:0)

首先注意声明:

char *a = { "jhsa", "asndb", "drtfe", "nhurh", "bvhr"};

不正确它应该是:

char *a[] = { "jhsa", "asndb", "drtfe", "nhurh", "bvhr"}; 

这是一个char指针数组。 a[i]中的每个索引都指向一个字符串文字。

问题在于您的比较功能。前两个数组是值数组,而a[]是一个指针数组。 阅读difference between char* str[] and char str[][] and how both stores in memory?以了解char* a[]的内存组织与char[][](二维继续分配的内存组织)的不同之处。

compare_()函数中传递a[i]的地址会发生什么情况(但不会将a[i]传递给自己)。当a[i]是值地址时,它可以找到,例如对于int[]char[][],而在char*[]的情况下,您没有传递值的地址而是传递值的地址。我认为你的主要困惑是在2D字符数组char[][]和文字字符串数组char*[]之间传递。

首先要了解你传递给比较函数的是什么,假设你有以下数组,那么你传递的是内容xyz的地址(即&amp; a [ i])但不是xyz(即[i])。

           a      
        +--------+
 343    |        |
        | a[0]=x | 
        |        |
        +--------+
        |        |
 347    | a[1]=y |
        |        |
        +--------+
        |        |
 351    | a[2]=z |
        |        |
        |        |
        +--------+
   * you are passing &a[i]

现在查看char a[5][20]的内存组织以防,因为&a[i]a[i]的内存组织值相同。检查以下代码及其输出:

#include<stdio.h>
int main(){
 char a[5][20] = { "jhsa", "asndb", "drtfe", "nhurh", "bvhr"};
 int i = 0;
 for(i = 0; i < 5; i++)
    printf(
        "&a[i] = %p, a[i] = %p, *a[i] = %c, string a[i] = \"%s\"\n", 
        (void*)&a[i], // you are passingg this &a[i]
        (void*)a[i],  // compare &a[i] and a[i] address value
        *a[i], 
        a[i]
    );
 return 0;
}

<强>输出

$ gcc x.c -Wall -pedantic -o x
$ ./x
&a[i] = 0x7fff1dfb28b0, a[i] = 0x7fff1dfb28b0, *a[i] = j, string a[i] = "jhsa"
&a[i] = 0x7fff1dfb28c4, a[i] = 0x7fff1dfb28c4, *a[i] = a, string a[i] = "asndb"
&a[i] = 0x7fff1dfb28d8, a[i] = 0x7fff1dfb28d8, *a[i] = d, string a[i] = "drtfe"
&a[i] = 0x7fff1dfb28ec, a[i] = 0x7fff1dfb28ec, *a[i] = n, string a[i] = "nhurh"
&a[i] = 0x7fff1dfb2900, a[i] = 0x7fff1dfb2900, *a[i] = b, string a[i] = "bvhr"

虽然&a[i]a[i]不相同但价值相同。要理解这些差异,请阅读Difference between &str and str, when str is declared as char str[10]?

但是&a[i]a[i]的值在char*[]的情况下不相同检查以下代码:y.c(类似于上面的x.c)及其输出:

#include<stdio.h>
int main(){
 char *a[] = {"jhsa", "asndb", "drtfe", "nhurh", "bvhr"};
 int i = 0;
 for(i = 0; i < 5; i++)
    printf("&a[i] = %p, a[i] = %p, *a[i] = %c, string a[i] = \"%s\"\n", 
        (void*)&a[i],
        (void*)a[i], 
        *a[i], 
        a[i]); 
 return 0;
}

输出

$ gcc y.c -Wall -pedantic -o y
$ ./y
&a[i] = 0x7fffa4674730, a[i] = 0x400690, *a[i] = j, string a[i] = "jhsa"
&a[i] = 0x7fffa4674738, a[i] = 0x400695, *a[i] = a, string a[i] = "asndb"
&a[i] = 0x7fffa4674740, a[i] = 0x40069b, *a[i] = d, string a[i] = "drtfe"
&a[i] = 0x7fffa4674748, a[i] = 0x4006a1, *a[i] = n, string a[i] = "nhurh"
&a[i] = 0x7fffa4674750, a[i] = 0x4006a7, *a[i] = b, string a[i] = "bvhr"

现在,&a[i]a[i]的通知值不同(实际上,偏移地址值显示不同的段并且a [i]获取堆栈中的地址空间,而a[i]获取地址空间字符串 literal 存储在哪里,但这是另一回事。)

因此,在字符串比较函数中:int compare_string()语句return strcmp(c, d);不适用于char*[],它应该类似于return strcmp(*c, *d);(虽然它适用于{{ 1}} char[][]&[i]的值相同的第一种情况我使用a[i]编译代码而-Wall它没有发出任何警告,所以我认为使用没问题它作为字符串地址 - 但我也不确定。因此,您需要一个单独版本的compare_string_ for -pedantic,您可以在其中调用char*[]。但现在问题是函数参数是strcmp(*c, *d);并且取消引用cont是未定义的行为。为了纠正您的代码,我从每个地方删除了cont void*,并为const添加了一个新功能int compare_string_v2( void *a, void *b),如下所示:

char* a[]

只需将您的代码编译为:int compare_string_v2( void *a, void *b) { char **c = a; char **d = b; return strcmp(*c, *d); } 它应该可以正常工作。在这里,您可以查看@ working instance of code

答案 2 :(得分:0)

您可以使用此代码,越简单越好! 首先在main()中编写Isless函数,有点像这样:

static int IsLess(void* num1, void* num2)
{
   return (*(int*)num1 > *(int*)num2) ? TRUE : FALSE;
}

然后使用此代码。

static void Swap(void* ptr1, void* ptr2, size_t _sizeof)
{
void* temp = malloc(_sizeof);
memcpy(temp,ptr2, _sizeof);
memcpy(ptr2,ptr1, _sizeof);
memcpy(ptr1,temp, _sizeof);
free(temp);
}
static void BubbleUp(int _end, void* _arr[], size_t _sizeofitem, fp _IsLess)
{ 
size_t j;
for(j = 0; j < _end; ++j)
{
    if(_IsLess((char*)_arr + j*_sizeofitem, (char*)_arr + (j+1)*_sizeofitem))
    {
        Swap((char*)_arr + j*_sizeofitem, (char*)_arr + (j+1)*_sizeofitem, _sizeofitem);
    }
}
}
void SortGen(void* _arr, size_t _sizeofitem, size_t _numOfItems, fp _IsLess)
{
int i;
if(_arr == NULL)
{
    return;
}
for(i = (int)_numOfItems -1; i >= 0; i--)
{
    BubbleUp(i, _arr, _sizeofitem, _IsLess);
}
}