使用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
看一看,任务成功完成!
现在回过头来解决最初的那个问题,相信此时已经不是问题了。
现在所有的问题都完美解决!原来的那个问题解决方法已经在上面的调试过程中有了!
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
看一看,任务成功完成!
现在回过头来解决最初的那个问题,相信此时已经不是问题了。
现在所有的问题都完美解决!原来的那个问题解决方法已经在上面的调试过程中有了!
相关文章推荐
- 存储过程使用逗号分隔作为IN参数疑难问题解决方法【真正解决】
- 使用内置函数解决PHP多维数组排序问题
- 使用C语言中qsort()函数对浮点型数组无法成功排序的问题
- play框架配置使用过程中遇到的各种疑难问题汇总(学习同事经验)
- Android系统Recovery工作原理之使用update.zip升级过程分析(二)---update.zip差分包问题的解决
- VS2005(c#)项目调试疑难问题解决方法锦集
- 使用GDB调试PHP代码,解决PHP代码死循环问题
- TIUDPClient使用过程中出了一个问题,请教一下怎么解决
- 在Sql语句中使用正则表达式来查找你所要的字符 及调试问题
- 基于UDP协议的网络摄像头的关键问题解决及调试过程
- Android系统Recovery工作原理之使用update.zip升级过程分析(二)---update.zip差分包问题的解决
- RFT使用过程中遇到的问题的解决方法(一)
- 转:ubuntu 下code blocks 安装全过程 && codeblocks 快捷键 && 解决调试终端不能粘贴问题
- 从一个字符数组中读出相应的整数、实数(有点问题,待调试,求大神帮忙)
- IE6,7,8下使用Javascript记录光标选中范围(已补全)(已解决单个节点内部重复字符的问题)
- VSRS_3.5使用过程中出现的问题解决
- 使用javaScript解决asp.net中mvc使用ajax提交数组参数的匹配问题
- netBeans使用过程中遇见问题及解决方法
- 对二维字符数组排序(2sort和1qsort)
- 在存储过程中声明参数时使用字符默认大小带来的问题?