关于学习NDK基础知识这些就够了(二)

一、指针的运算
指针的类型:
指针有类型,地址没有类型
地址只是开始的位置,类型读取到什么位置结束

1、常量指针:
首先它是一个指针,常量只是用来修饰指针的定语。其定义如下:

char const * cp; 
char a='a'; 

如何识别呢?根据右结合优先,先是优先,所以这个cp变量是一个指针,然后是const修饰,所以这是一个常量指针。即指向常量的指针。

cp=&a; //正常语法 
*cp=a; //错误语法,因为其指向的值是一个常量 

2、指针常量:
首先它是一个常量,指针是用来修饰常量的,即常量的值为一个指针地址。


char * const cp; 
char a='a'; 

如何识别呢?根据右结合优先,先是const优先,所以这个cp变量是一个常量,然后是*修饰const,所以这是一个指针常量。

cp=&a; //错误语法,因为其地址为是一个常量
*cp=a; //正确,地址所指向的内容是一个普通字符

注意和上边区分开

3、指针数组:
首先它是一个数组,指针是用来修饰数组内容的,表示什么样的数组 :即存放指针的数组

char *arr[3] = {"1","123","345"}; 

如何识别,因为[]的优先级大于,所以先是定义为一个数组,而后由来修饰这个数

printf("arr0%c\n",*arr[0]); 
printf("arr1%s\n",arr[1]); 

4、数组指针:
首先它是一个指针,数组是修饰指针的,即指向数组的指针。

char (*p)[3];  //申明时不能同时初始化 
char arr[3] = {'1','4','7'}; 
p=&arr; //指向数组的首地址,同时指针的类型是char * [3] 类型的,即加1操作后为sizeof(char [3])


如何识别:因为这次添加了一个显示优先,所以这次先是一个指针,而后[]修饰指针

printf("%c\n",(*p)[0]);  //先取arr的首地址,再根据这个地址取数组内容 
printf("%c\n",(*p)[1]); 
printf("%c\n",(*p)[2]); 
printf("%c\n",*((char*)p+0)); //先转换为char指针,再取值 
printf("%c\n",*((char*)p+1)); 
printf("%c\n",*((char*)p+2)); 
printf("%c\n",((char*)p)[0]); //先转换为char指针,再取数组的值,和第一个类似 
printf("%c\n",((char*)p)[1]);  
printf("%c\n",((char*)p)[2]);  

5、函数指针:
首先它是一个指针,函数是修饰指针的,即指向函数的指针。

char (*func)(void); //定义函数指针 
char test(void)  
{ 
return 'A'; 
} 
func = test;  //初始化赋值 
printf("test address: %p\n",test); 
printf("func address: %p\n",func); 
char ch = func();  //调用 
printf("%c\n", ch); 

实例:

int msg(char* msg,char* title){
    MessageBox(0,msg,title,0);
    return 0;
}
void main(){
    //msg();
    printf("%#x\n",msg);
    printf("%#x\n",&msg);
    //函数指针
    //函数返回值类型,函数指针的名称,函数的参数列表
    int(*fun_p)(char* msg, char* title) = msg;
    fun_p("消息内容","标题");

    getchar();
}

如何识别,同数组指针一样,因()的优先级,所以这个定义首先是一个指针,而后才是对指针的描述,即一个指向函数的指针,其指向的函数也是规定的:即返回的是字符类型,不需要传入参数

6、指针函数:
首先它是一个函数,指针修饰函数的返回类型,即一个返回指针的函数

char *func(void); 

如何识别,因为没有扩弧,所以的优先级没有右边的扩弧优先级高,所以先是规定了一个函数,只是修饰返回值的

char *func(void) { 
  char *str = "test"; 
  return str; 
 } 
 void main() { 
  char *test = func();  
  printf("%s\n",test);  
} 

7、指针为什么要有类型?
指针有类型,地址没有类型
地址只是开始的位置,类型读取到什么位置结束

void main(){
    int i = 89;
    //int 类型的指针
    int *p = &i;
    double j = 78.9;
    //赋值为double类型变量的地址
    p = &j;
    printf("double size:%d\n", sizeof(double));
    printf("%#x,%lf\n",p,*p); //想通过4字节读取8字节变量的值,是不行的    

    getchar();
}

8、指针类型转换:

指针类型转换是个有意思的东西,你可以把一个int型的指针转换为char类型,然后再把char类型的指针转换为int型;就像普通的字符和int型之间的转换一样。但指针转换后其值没有变,唯一变的东西就是指针的步长,即进行指针运算时的计算方式。当为char指针时其运算单位均以1个字节为1个运算单位,而当为int指针时通常都是以4个字节为1个运算单位。

9、指针算术:

根据上面的指针类型转换介绍可知,不同的指针类型进行算术运算时其计算方式时不相同的,其不同之处就在于其步长的字节数不同,而具体其步长为几个字节数是以其指针类型决定的,指向char的指针步长即为1。通常的指针运算有指针与数字的加减运算,相同类型的指针的减法运算,而且还要是指向同一个数组的,不然意义不大。同理推得不同类型的指针进行运算意义更不大,甚至会报错。
下面举一个指针算术的例子,交换两个变量值不利用额外变量
毕竟new关键字还是申请了额外的内存,虽然没有申请变量,换汤未换药



int *a,*b;   
a=new int(10);    //给指针赋值 
b=new int(20);    //a=0x00030828,b=0x00030840 
a=(int*)(b-a);    //a=0x00000006 
b=(int*)(b-int(a));  //b=0x00030828 
a=(int*)(b+int(a));  //a=0x00030840 

只是交换变量的话也可以:

int a = 4; 
int b = 5; 

*(((char*)&a)+1) = *((char*)&b); 
*((char*)&b)=*((char*)&a); 
*((char*)&a)=*(((char*)&a)+1); 
*(((char*)&a)+1)=0; 

实例:

void main(){
    //数组在内存中连续存储
    int ids[] = { 78, 90, 23, 65, 19 };
    //数组变量名:ids就是数组的首地址
    printf("%#x\n",ids);
    printf("%#x\n",&ids);
    printf("%#x\n",&ids[0]);
    //指针变量
    int *p = ids;
    printf("%d\n",*p);
    //指针的加法
    p++; //p++向前移动sizeof(数据类型)个字节
    printf("p的值:%#x\n", p);
    //p--;
    printf("%d\n", *p);
    getchar();
}

10、NULL空指针

void main(){
    int i = 9;
    int *p = NULL;
    //p = &i;

    //空指针的默认值为0
    printf("%#x\n",p);
    //访问内存地址0x000000操作系统不允许
    //p = 100; //操作系统不允许访问
    printf("%d\n",*p);
    getchar();
}

通过指针给数组赋值

void main(){
    int uids[5];
    //高级写法
    //int i = 0;
    //for (; i < 5; i++){
    //  uids[i] = i;
    //}
    //早些版本的写法
    int* p = uids;
    printf("%#x\n",p);
    int i = 0; //i是数组元素的值
    for (; p < uids + 5; p++){
        *p = i;
        i++;
    }

    getchar();
}

11、多级指针(二级指针)

指针保存的是变量的地址,保存的这个变量还可以是一个指针变量
动态内存分配给二维数组

void main(){
    int a = 50;
    //p1上保存的a的地址
    int* p1 = &a;

    //p2上保存的p1的地址
    int** p2 = &p1;

    //int*** p3 = &p2;

    printf("p1:%#x,p2:%#x\n",p1,p2);
    **p2 = 90;

    printf("%d\n",a);

    getchar();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值