您的位置:首页 > 其它

使用qsort对二维字符数组排序疑难问题调试及解决过程

2009-07-14 19:40 507 查看
先说说我这个程序的场景。我程序中有一个二维数组,代码段如下:

char
files[101][64];
// files[i][0] sotres the length of the i-the file name

正如注释中说的,
files[i
][0]
用来存储
files[i
]
这个字符串的长度,字符串是从
files[i
][1]
开始存储的,每个字符串长度保证不超过
60,
所以才考虑这样来存储。现在突然发现在字符串都存储到
files
中去后,必须还要对
files
中的字符串进行排序。如果是使用
c++

string
来写当然没问题,但是既然代码已经写成这样,就没再重写,而是打算用
C

qsort

来排序,这也是一个很有挑战性的工作。

对于自己的代码,先后尝试了很多办法也没能让它正确工作,最终想到调试
MSDN
上给出的那个使用
qsort

对字符串进行排序的程序。那个程序如下:

#include
<stdlib.h>

#include
<string.h>

#include
<stdio.h>

int
compare( const
void
*arg1, const
void
*arg2 );

void
main( int
argc, char
**argv )

{

int
i;

/* Eliminate argv[0] from sort: */

argv++;

argc--;

/* Sort remaining args using Quicksort algorithm: */

qsort( (void
*)argv, (size_t)argc, sizeof
( char
* ), compare );

/* Output sorted list: */

for
( i = 0; i < argc; ++i )

printf( "%s "
, argv[i] );

printf( "/n"
);

}

int
compare( const
void
*arg1, const
void
*arg2 )

{

/* Compare all of both strings: */

return
_stricmp( * ( char
** ) arg1, * ( char
** ) arg2 );

}


qsort

调用那一句设置断点,为了看看
argv

是什么指针类型
(

char**
还是
char(*)[])
,同时看看调用
qsort

时传递的第一个参数的值是多少,另外在
compare
上设置断点,为了看看这个函数被回调时实参的值是多少。
(
这个程序的命令行参数是
this is a test.)

单步,执行到
qsort

,此时
argv


type

char**

value

0x003a4ee4
,这段内存的内容是:

0x003A4EE4

35 4f 3a 00 3a 4f 3a 00 3d 4f 3a 00 3f 4f 3a 00 00 00 00 00 64 3a 5c 4d 79 44 6f 63 75
5O:.:O:.=O:.?O:.....d:/MyDocu

0x003A4F01

6d 65 6e 74 73 5c 56 69 73 75 61 6c 20 53 74 75 64 69 6f 20 32 30 30 35 5c 50 72 6f 6a
ments/Visual Studio 2005/Proj

0x003A4F1E

65 63 74 73 5c 4a 4f 4a 5c 64 65 62 75 67 5c 4a 4f 4a 2e 65 78 65 00 54 68 69 73 00 69
ects/JOJ/debug/JOJ.exe.This.i

0x003A4F3B

73 00 61 00 74 65 73 74 2e 00 fd fd fd fd ab ab ab ab ab ab ab ab fe ee fe ee fe ee fe
s.a.test.....................

可以看到,在
argv

的值指示的地址处不是字符串,而是几个指针,再根据指针所指向的内在查看一下,恰恰是那几个字符串的地址,这样,这个程序就没什么难理解的,现在改一下这个程序,看看这个模式是不是可以在普通的二维字符数组上实现。主要改动了以下代码,改动后是:

char
data[4][16] = { "this"
, "is"
, "a"
, "test."
};

/* Sort remaining args using Quicksort algorithm: */

qsort( (void
*)data, (size_t)4, sizeof
( char
* ), compare );

上述对于
qsort

的调用就是做了个替换,把以前的
argv

替换成了
data
,把以前的
argc

替换成了
4,
运行,出现异常。异常信息是说在
stricmp.c

文件的
98
行,一个
assret

(dst
!= NULL)
的断言失败了。于是,对这个修改后的程序进行调试,看看差别在哪里:

运行到
qsort

调用,
data

type

char[4][16]

value

0x0012ff14
。查看这个内存地址,发现这个内存地址处的值就是那几个字符串。坏了,没有一个二级指针指向它们!现在结果已经可以预料到,那就是
qsort

以为传给它的是一个二级指针数组的首地址
(
但我们传给它的实际上却是
data
,是直接指向字符串的!
)
,所以
qsort


data
的地址开始,即从
0x0012ff14
开始,读取四个字节,把这四个字节作为指针,去检索内存!为了验证这个想法,继续
F5
到下一个断点:果然如此!执行到
compare
函数,两个参数的值是
0x0012ff14, 0x0012ff18


怎么办!我们必须传给
qsort

函数这样的一个序列:
&data[0]

&data[1], &data[2], &data[3]
。在调试器里面看到,
&data[0] = 0x0012ff14, &data[1] = 0x0012ff24, &data[2] = 0x0012ff34, &data[3] = 0x0012ff34
。现在,抱着这样的希望,再次修改
qsort

函数调用:

qsort( (void
*)data, (size_t)4, sizeof
( char (*)[16]

), compare );

红字并加粗的部分是我修改过的,这时候再调试看看。但我发现自己搞错了,
qsort

的第三个参数是
size_t

类型,我却又传递进去一个指针,任何指针的类型都是
4
个字节。修改成这样试试:

qsort( (void
*)data, (size_t)4, 16

, compare );

执行到
compare
函数,
YES!!!

这一次两个参数的值是
0x0012ff14,0x0012ff24
,但还是异常了,问题出在
compare
函数上面,这一次传进去的指针可完全是字符串首地址了,所以,把
compare
函数由原来的:
int
compare( const
void
*arg1, const
void
*arg2 )

{

/* Compare all of both strings: */

return
_stricmp( * ( char
** ) arg1, * ( char
** ) arg2 );

}

修改为:

int
compare( const
void
*arg1, const
void
*arg2 )

{

/* Compare all of both strings: */

//return _stricmp( * ( char** ) arg1, * ( char** ) arg2 );

return
_stricmp((char
*)arg1, (char
*)arg2);

}

这一次再运行程序,
OK!

没有异常!


遗憾的是没有改输出,这次输出排序后的
data
看一看,任务成功完成!


现在回过头来解决最初的那个问题,相信此时已经不是问题了。

现在所有的问题都完美解决!原来的那个问题解决方法已经在上面的调试过程中有了!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐