Android NDK开发之C语法(指针相关)

前言 :建议加上宏定义:允许使用过时的函数和不安全的函数,去掉警告
#define _CRT_SECURE_NO_WARNINGS
此篇文章为笔记型文章。方便笔者日后快速复习~~

导包语法:#include <xxx.h>
常用包:

  • stdio 标准函数库
  • stdlib 标准函数库(system、sizeof等等…)
  • Windows windows系统的api
    函数入口:
//导入标准函数库(类似于java的导包)
#include <stdio.h>
//导入标准函数库(system、sizeof等等......)
#include <stdlib.h>
//windows系统的api
#include <Windows.h>

void main(){
	//输出函数
	printf("hello world!");
	//这是一个命令(在window里面特有的)
	system("pause");
}

基本数据类型(int char float double long int short)

占位符:
%d - int
%ld – long int
%c - char
%x - short
%f - float
%u – 无符号数
%hd – 短整型
%lf – double
%x – 十六进制输出 int 或者long int 或者short int
%#X - 显示十六进制
%o - 八进制输出
%s – 字符串

输入输出函数:

//输出函数
printf("请输入一个整数:");
//输入函数(注意:输入函数赋值需要的是地址,而不是值)
//scanf("%d",&i);
//注意:不同编译工具,对函数支持不一样
scanf_s("%d", &i);

内存地址&指针:

int i = 100;
//输出i的值
printf("i的值:%d\n",i);

//输出i的地址
//&i:取出i变量的地址
//注意:输出地址,占位符%p
printf("i的地址:%p\n",&i);

//根据地址获取值:*(&i)
//总结:&表示取地址  *表示根据地址取值
printf("根据i的地址取出i的值%d\n",*(&i));

//什么是变量名:就是对内存的一段空间里的数据的抽象
//0x001CFDD0

多级指针

int i= 99;
//打印i的值
printf("%d\n",i);
//打印i的地址
printf("%p\n", &i);

//定义一个指针变量
//int* 是一个int类型的指针变量,可以存储一个int类型的变量地址
int* p = &i;
printf("指针变量p的值:%p\n",p);

//输出指针的地址
printf("指针变量p的地址:%p", &p);

//直接赋值
i = 200;
printf("变量i的值:%d\n", i);
//间接赋值(通过指针变量)
*p = 500;
printf("指针变量赋值后的i的值:%d\n", i);

通过指针学习,可以在方法中传递指针地址,在方法内部通过指针地址变量操作真实数据。

方法形参若为真实变量形参,例如:int a; 则会在方法内为a开辟一个新内存。修改a的值并不能修改原始值。

指针和地址的区别:指针有类型,地址没有类型。

指针需要通过类型判断开辟多大内存空间,例如int 开辟4字节。char开辟两字节。

指针必须要有初始值。可以为NULL,但是不能不赋值。否则会报错

多级指针另一种写法:int** p2 = &p1;

p2保存的数据是p1地址,*p2上的数据是p1上面数据, p1保存的数据是a的地址,**p2实际上就是a的值

数组

数组遍历

总结一:ids常量指针,存储的是数组的首地址
总结二:数组在内存中排列是连续不断(线性排列)

int ids[] = {23,15,67,38,99,70};
//打印数组
//printf("数组:%#x\n", ids);
//数组第一个元素地址
//printf("数组第一个元素地址:%#x\n",&ids[0]);

//总结:p++每次向前移动sizeof(数据类型)个字节
int* p = ids;
//p++;
//printf("地址:%#x  值:%d", p, *p);

//遍历数组
//传统方式
//int i = 0;
//for (; i < 6; i++){
	//printf("值:%d\n", ids[i]);
//}
//通过指针遍历
for (; p < ids + 6; p++){
	printf("地址:%#x   值:%d\n",p, *p);
}

//注意:让指针递增或者递减,一般情况下只有在数组遍历的时候才有意义,
//基于数组在内存中是线性排列的方式(连续不断)

数组赋值

int ids[6];
int* p = ids;
//传统写法(高级写法)
//赋值
//int i = 0;
//for (; i < 6; i++)
//{
	//ids[i] = i;
//}

//指针方式赋值
int i = 0;
for (; p < ids + 6; p++){
	*p = i;
	i++;
}

数组遍历于指针关系分析

int ids[] = { 23, 15, 67, 38, 99, 70 };
int i= 0;
for (; i < 6; i++){
	//输出-高级写法(常规写法)
	//printf("%d  %#x\n", ids[i], &ids[i]);

	//之前分析了ids就是常量指针,就是一个首地址
	//以下分析是取地址
	//分析:ids是首地址
	//ids+0 等价于 &ids[0]
	//ids+1 等价于 &ids[1]
	//以此类推......
	//总结:ids+i 等价于 &ids[i]
	//分析取值
	//*(ids+0) 等价于 ids[0]
	//*(ids+1) 等价于 ids[1]
	//以此类推......
	//总结:*(ids+i) 等价于 ids[i]
	printf("%d  %#x\n",*(ids+i),ids+i);
}

二维数组

//两行三列-二维数组
int ids[2][3] = { 23, 15, 67, 38, 99, 70 };
//遍历二维数组:外层循环控制行,内层循环控制列
int i = 0;
for (; i < 2; i++){
	int j = 0;
	for (; j < 3; j++){
		printf("值:%d 地址:%#x       ", ids[i][j],&ids[i][j]);
	}
	printf("\n");
}

二维数组推理分析:

//打印第二行,第二列
printf("%d\n",ids[1][2]);

//推导
//ids + 0 代表第一行  第一行的第一个值
//ids + 1 第二行(下一行)  第二行的第一个值
//以此类推:ids + i
//取每一行第一个元素的指针:*(ids+i)
//第一行第一个元素指针:*(ids+0)
//第二行第一个元素指针:*(ids+1)
//以此类推:*(ids+i)

//继续推理
//取第一行第一个指针:*ids + 0
//取第一行第二个指针:*ids + 1
//取第一行第三个指针:*ids + 2
//以此类推:*ids + j

//继续推理
//取第一行第二个指针:*(ids+0)+1
//取第二行第二个指针:*(ids+1)+1
//以此类推:*(ids+i)+j(这个公式获取的是地址,是一个指针变量)
//*(*(ids+i)+j)

printf("%d", *(*(ids+1)+2));

指针比较

指针运算-指针大小比较
指针大小比较:都是在遍历数组的时候运用,其他情况下没什么用
指针相等比较:指针地址相等,并不代表值相等,因为指针有类型,例如:

int* p1 = (int*)0x006578;
double* p2 = (double*)0x006578;

函数指针

void showMessage(){
}
void add(int a, double b){
}
void main(){
	//传统的写法
	//直接调用
	//showMessage();
	
	//采用函数指针的方式调用
	//void(*p)() = showMessage;
	//p();

	//带返回值和参数列表的函数指针
	double(*p1)(double a, double b) = add;

	double d = p1(2,3);
	printf("%lf", d);

	//补充:函数指针-不仅仅是地址,必须明确的指定函数的指针类型,以及返回值和参数列表
	//回想Java语言:方法重载(方法名相同,参数列表不同,或者参数类型不同)
	getchar();
}

动态内存分配

malloc 分配内存
calloc 分配内存(更方便)

int* p = (int*)malloc(5 * sizeof(int));
//第一个参数:数组长度
//第二个参数:每个元素大小
int* p = (int*)calloc(5,sizeof(int));

free 回收内存
free(p)
realloc 重新分配内存
int* p1 = (int*)realloc(p,sizeof(int)*(len+addLen));

注:新的=老的+增加的
realloc更改已经配置的内存空间

  • 缩小:会导致一部分数据丢失
  • 扩大(连续不断-线性排列)
    • 情况一:如果当前的内存段后面有需要的内存空间,就会直接追加(注意:返回原指针)
    • 情况二:如果当前内存段后面空闲的字节空间不够,就会重新再堆内存中寻找能够容纳该数据大小的内存区域(注意:返回值新的内存地址,原来的被释放)
    • 情况三:如果没有容身之处,申请内存失败,将返回NULL,而且原来的指针有效

内存分配注意事项:

1、不能够多次释放内存
2、释放内存之后,给原来的指针设置NULL
3、内存泄漏

int* p = (int*)calloc(5, sizeof(int));
...一顿操作...
//释放内存
free(p);
//标记内存已经被释放
p = NULL;

如下会导致内存泄漏
//在堆区开辟了一块40M的内存空间
int* p = (int*)malloc(1024 * 1024 * 10 * 4);
p = NULL;
//回收内存
free(p);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值