最近为了做一题字符串排序的题目,花了我不少时间,现在把它记下来,作为学习笔记吧
首先要知道什么是指针数组?
指针数组:是一个存放指针的数组,数组的每个元素都是一个指针。
注意:要与数组指针区分开来,数组指针是指向数组的指针。
举个列子:
char *arr[5];//它是一个存放有5个指针,每个指针都指向一个字符串的数组
下面举个简单的例程:
char *k[2];
char *q[2] = {"abc","345"};
printf("addk:%p,addq0:%p,addq1:%p\n", k[0], q[0],q[1]);//查看初始时三个指针的值
k[0] = q[0];
printf("addk:%p,addq0:%p,addq1:%p\n", k[0], q[0],q[1]);//下面依次查看交换后三个指针的值
q[0] = q[1];
printf("addk:%p,addq0:%p,addq1:%p\n", k[0], q[0],q[1]);
q[1] = k[0];
printf("addk:%p,addq0:%p,addq1:%p\n", k[0], q[0],q[1]);
printf("q0:%s\nq1:%s\n", q[0], q[1]);//打印指针数组交换后的值
如上程序,当执行 k[0] = q[0]; 后 k[0] 的值发生了改变,即指针k[0]的值和 q[0]的值相同,这样他们指向的地址都是字符串 “abc” 的地址,所以 k[0] = q[0]; 执行的结果是地址的赋值和改变,而非地址所指向的内存存放的数值的赋值和改变。
如果执行下面的语句,编译时不一定会报错,但是执行会出错:
函数执行的是对字符串的拷贝,而非地址的赋值,但是如果 k[0] 和 q[0] 都是对应的二维数组的地址话则是可以正常赋值的
strcpy(k[0],"aaa")//这样也是不行的,strcpy 只能对单纯的数组进行操作
q[0] = "ccc";//这样是可以的
如果对指针数组单独赋字符串则是可以的如:
下面贴一下我的字符串转换的代码:#include //预定义与宏定义
#include
#define LEN 5
#define WIDE 5
void sortlist(char *string[], int num); //函数的声明
void printlist(char *string[], int num);
int main(){ //主函数
int i = 0;
char *str[LEN] = {"dbcd", "aacd", "bace", "esae", "aede" };//要比较的字符串
for(i = 0; i < LEN; i++){ //先打印出要显示的字符串
printf("%s\t",str[i]);
}
printf("\n");
sortlist(str, LEN); //从小到大的排序
printlist(str, LEN); //打印出排序后的字符串
return 0;
}
void sortlist(char *string[], int num){ //排序函数体
char *temp;
int i = 0;
int j = 0;
for(i = 0; i < num-1; i++){ //使用冒泡排序法
for(j = 0; j < num-1 ; j++){
if(strcmp(string[j],string[j+1]) == 1){ //用字符串比较函数进行比较两个字符串
temp = string[j];//进行地址交换
string[j] = string[j+1];
string[j+1] = temp;
}
}
}
}
void printlist(char *string[], int num){ //打印函数体
int i = 0;
for(i = 0; i < num; i++){
printf("%s\t",string[i]);
}
printf("\n");
}
//执行结果
dbcd aacd bace esae aede//要排序的字符串
aacd aede bace dbcd esae//排序后的字符串
好了下面讲一个有意思的程序:
#include
void swap(int *ap, int *bp);
int main(){
int a = 10;
int b = 20;
int *ap,*bp;
ap = &a;
bp = &b;
printf("a:%d , b:%d\n" , a , b);
printf("ap:%p , bp:%p\n", ap , bp);
swap(ap, bp);
printf("a:%d , b:%d\n", a , b);
printf("ap:%p , bp:%p\n", ap , bp);
return 0;
}
void swap(int *ap, int *bp){
int *n;
// int *_ap , *_bp;
// _ap = a;
// _bp = b;
// n = _ap;
// _ap = _bp;
// _bp = n;
n = ap;
ap = bp;
bp = n;
printf("swap_ap:%p , swap_bp:%p\n", ap , bp);
printf("swap_a:%d , swap_b:%d\n", *ap, *bp);
}
//执行结果如下
main_a:10,main_b:20 //未交换前的值
main_ap:0xbff9c31c,main_bp:0xbff9c318 //未交换前的定义的两个指针
swap_ap:0xbff9c318,swap_bp:0xbff9c31c //交换函数中指针交换后的值,可以看到函数中地址是有交换的
swap_a:20,swap_b:10 //交换函数中a和b的值,a和b的值也是有交换的
main_a:10,main_b:20 //交换后main函数中a和b的值,很显然a和b的值并没有交换
main_ap:0xbff9c31c,main_bp:0xbff9c318 //相应的地址也没有改变
为什么?
在执行交换函数时,传递到函数中的形参在函数中进行了一份拷贝,之后所有的操作都是对拷贝进行的,如上面的注释部分:
int *_ap , *_bp;
_ap = a;
_bp = b;
n = _ap;
_ap = _bp;
_bp = n;
a = _ap;
b = _bp;
当结束交换函数时,函数中的变量被释放,所以并没有交换主函数中a和b的地址。
那么为什么用字符数组却可以呢?
首先看一个这样的例程:
#include
void swap(int **ap, int **bp);
int main(){
int a = 10;
int b = 20;
int *ap,*bp;
ap = &a;
bp = &b;
printf("main_a:%d,main_b:%d\n",a,b);
printf("main_ap:%p,main_bp:%p\n",ap,bp);
swap(&ap, &bp);
printf("main_a:%d,main_b:%d\n",a,b);
printf("main_*ap:%d,main_*bp:%d\n",*ap,*bp);
printf("main_ap:%p,main_bp:%p\n",ap,bp);
return 0;
}
void swap(int **ap, int **bp){
int *n;
n = *ap;
*ap = *bp;
*bp = n;
printf("swap_ap:%p,swap_bp:%p\n",*ap,*bp);
printf("swap_a:%d,swap_b:%d\n",**ap,**bp);
}
//函数的执行结果如下
main_a:10,main_b:20
main_ap:0xbf9ffc3c,main_bp:0xbf9ffc38
swap_ap:0xbf9ffc38,swap_bp:0xbf9ffc3c
swap_a:20,swap_b:10
main_a:10,main_b:20
main_*ap:20,main_*bp:10 //主函数中的指针所指向的值交换了
main_ap:0xbf9ffc38,main_bp:0xbf9ffc3c //指针的地址变化了
用上面这个函数替换上面的swap函数,可以成功实现a和b值的交换。
注意:这里看到的a和b值的交换是用指针进行观察的,而a和b的原值是不会被改变的,因为它们都是局部变量。其实也就是说改变的是指针的值,即地址。
上面的函数就解释了为什么指针数组可以实现交换,因为使用指针数组时,传递给swap函数的是指向指针的指针,对指针数组的操作就是对指针指向的指针的操作。
文章不是很完善,后期可能会有修改。