字符指针数组(二级指针)

一、字符指针数组 - 1

1、字符指针数组概念

字符指针数组是指一个数组中的各个元素都是字符指针
或者是字符串(字符数组)的首地址

2、初始化

char *name[]={"zhangsan","lisi","wangwu"};

变量名联系:

实际存值: name[0]=&'z' , name[1]=&'l' , name[2]=&'w'
间接功能: name[0]="zhangsan" , name[1]="lisi" , name[2]="wangsu"

3、存储方式

见->变量名联系
*每个元素存储的是字符串的[首地址]
eg:首 地 址:
&’z’ , &’l’ , &’w’
内部元素:
‘z’ , ‘h’ , ‘a’ , ‘n’ , ‘g’ , ‘s’ , ‘a’ , ‘n’
‘l’ , ‘i’ , ‘s’ , ‘i’
‘w’ , ‘a’ , ‘n’ , ‘g’ , ‘w’ , ‘u’
内部元素的地址对应的数据,是存放在常量区->不可修改
元素首地址存放到了names指针数组中,即其元素

*优先考虑字符指针数组存放字符串
 减少 排序/交换等操作 时的内存消耗

4、示例程序

#include <stdio.h>
int main(void)
{
    char *names[]={"zhangsan","lisi","wangsu"};
    printf("names[0]: %s , names[0]: %p\n",names[0],names[0]);
    *(names[0])='Z';  //段错误,存在字符串常量区,不可修改!
    return 0;
}

二、字符指针数组 - 2

1、字符指针数组相关概念

names两种理解:
names数组里的第一个元素(值)
字符常量数组里第一个字符串的首地址:&’z’

程序运行中,出现了两个地址

2、概念理解

两个地址:

第一个地址,每个字符串常量的地址,和字符指针数组里面的元素的值,依次一一对应相同
第二个地址,字符指针names中的元素,需要存放的地址,这些地址值以元素的形式存放在PP指针数组里
以上构成 一级指针 和 二级指针

两种访问字符指针数组方式:

下标访问 | 二级指针(指针的指针)访问

3、深入理解二级指针概念:

p:一级指针变量(名)
a=10 p=&a
&a: 一级指针

&a->p &p->pp
pp:二级指针变量(名)
&p二级指针

解释:
二级指针变量名(二级指针里面第一个元素值)
等于一级指针变量名(一级指针里面第一个元素的值)的地址
(即: pp0= &p(地址) = names0)
等于字符指针数组(常量)(zhangsan)的地址

4、示例程序:
利用二级指针遍历字符指针数组,打印出字符串常量

#include <stdio.h>
//下标遍历
void out_name(char *names[],int n)
{
    int i;
    for(i=0;i<n;i++)
    {
        printf("%s ",names[i]);
    }
    printf("\n");
}

//二级指针遍历
void out_name2(char **pp,int n)
{
    int i;
    for(i=0;i<n;i++)
    {
        printf("%s ",*(pp+i));//*(&names[0])  *(pp+i)
        //pp是指针,加上地址偏移量i,就是在指向p里面的元素
        //*(p里面的元素) = names数组每个字符串的首地址
    }
    printf("\n");
}

int main(void)
{
    char *names[]={"zhangsan","lisi","wangsu"};
    printf("names[0]: %s , names[0]: %p\n",names[0],names[0]);
    out_name(names,3);
    out_name2(names,3);//names 两种理解
    return 0;
}

三、字符指针数组 - 3

1、字符指针数组中存放的是字符串(字符数组)的首地址
而字符串本身存放在常量区,是不能被修改的

2、字符指针数组存储字符串要比字符数组存储字符串的开销小
操作时(如排序、交换)占用内存小

3、两种利用二级指针寻址的方式(排序)

1. void sort(char *names[],int n)
   {
        int i,j,pos;
        for(=0;i<n-1;i++)
        {
            pos = i;
            for(j=i+1;j<n;j++)
            {   
                //字符串的首地址
                if(strcmp(names[i],names[pos])<0)
                {
                    //position 始终指向小值
                    pos = j;
                }

            }

        }
        if(pos != i)
        {
            char *temp;
            temp = names[pos];
            names[pos] = names[i];
            names[i] = temp;
        }

   }

2. void sort2(char **p,int n)
   {
        int i,j,pos;
        for(=0;i<n-1;i++)
        {
            pos = i;
            for(j=i+1;j<n;j++)
            {   
                //字符串的首地址
                if(strcmp(*(pp+j),*(pp+pos))<0)
                {
                    //position 始终指向小值
                    pos = j;
                }

            }

        }
        if(pos != i)
        {
            char *temp;
            temp = *(pp+pos);
            *(pp+pos) = *(pp+i);
            *(pp+j) = temp;
        }

   }

四、字符指针数组 - 4

1、带参主函数->字符指针数组获取命令行参数的
格式:int main(int argc,char *argv[])
解释:
argc 记录传入函数的参数个数
(包括可执行文件->0开始,不包括可执行和文件->1开始)
argv 记录成功传入函数的参数内容
(包括可执行文件->0开始,不包括可执行和文件->1开始)

案例:

#include <stdio.h>
int main(int argc,char *argv[])//第二参数换成二级指针:char **argv
{
    printf("argc:%d\n",argc);
    int i;
    for(i=1;i<argc;i++)
    {
        printf("%s",argv[i]));    //下标法 
        //printf("%s",*(argv+i));   //指针法
    }
    printf("\n");
    return 0;
}

1> 下标法->argv[i])

运行:bin/args_main 1 2 3 4 5
(1 2 3 …都是读取入该字符串首地址)

argc:6 (带上了可执行纪文件)
1 2 3 4 5
argv[i]从1开始,因为bin/a.out占用了0

eg:
gcc args_main -o args_main.c
args_main 替换 a.out
{运行:bin/args_main ni hao ma
原理:读入带参函数的是字符串首地址:
&’n’、&’h’、&’m’

输出:
argc:4 (带上了可执行文件)
ni hao ma

如果是从argv[0]开始则输出为:
argv:4
bin/args_main ni hao ma
}

2> 指针法->*(argv+i)

第二参数换成二级指针:char **argv
原理同 下标法

五、字符指针数组 - 案例

1、内容:

根据姓名查找学生是否存在
char *students[]
二级指针->遍历一维字符指针数组
“结束标志:”NULL””

2、代码

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

int find(char **pp,char *name);
//第一个参数:    
//第二个参数:待查学生姓名首地址
int main(void)
{
    int result;
    NULL:在这里作空指针
    char *students[]={"zhangsan","lisi","wangwu",NULL};
    char name[20]={'\0'};
    printf("Please Input Student's Name: ");
    scanf("%s",name);
    //students:该字符指针数组的->首地址
    result = find(students,name);
    if(result)
    {
        printf("find !");
    }
    else
    {
        printf("not find !");
    }

}

int find(char **pp,char *name)
{
    //Tips: 对入参数进行判断
    if(pp == NULL||name == NULL)
    {
        return 0;  //返回为->假
    }
    while(*pp != NULL)
    {
        if(strcmp(*pp,name)==0)
        {
            return 1;  //找到了返回为->真
        }
        else 
        {
            pp++;  //找下一个
        }
    }
    return 0; //遍历完了还没找到则: return false

}

要点:

NULL作为最后结尾标志
pp++超出字符指针数组存储范围后
容易产生段错 -> 越界导致

  • 12
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值