NDK开发之C基础回顾2

指针为什么要有类型?

1、类型表明指针指向的值是什么类型的,比如int类型的指针指向double类型的值,只能指向4个字节,类型告诉你读到哪里结束
2、地址只是开始的位置,类型告诉你读取到什么位置结束
3、指针有类型,地址没有类型

指针使用规范?

NULL空指针,其值为0,访问0X000000是不允许的,操作系统不允许。

多级指针(一般只使用到二级指针)

指针保存的是变量的地址,保存的这个变量还可以是一个指针变量。
int a = 90;
int *p1 = &a;
int **p1 = &p1;

指针运算

指针的加法,p++向前移动sizeof(数据类型)个字节
数组在内存中连续存储。指针的运算,一般在数组便利时才有意义,基于数组在内存中现行排列的方式。

指针函数

int add(int x, int y) {
return a + b;
}

int minus (int a , int b) {
return a - b;
}

//msg需要一个传递一个函数指针函数参数
void msg (int (*fun_p) (int a, int b)) {
int r = fun_p(a, b);
    printf("%d", r);
}

int main() {
    //加法
    msg(add, 20, 20);
    //减法
    msg(minus, 50, 20)l
}

C语言内存分配

1、栈区(stack)
    window下,栈内存分配2M(确定的常数),超出了,就会提示stack overflow错误,自动分配自动释放。
2、堆区(heap)
程序员手动分配释放,操作系统80%内存 

在堆内存分配40M的空间,传递的参数是字节
int *p = malloc(1024*1024*10*sizeof(int));

//释放
free(p)

创建一个数组,动态制定数组的大小
//静态内存分配创建数组,数组的大小是固定的
int i = 10;
int a[i];

int len ;
scanf("%d", &len)
int *p = malloc( len * sizeof(int) );
//给数组元素辅助,(使用这一块刚刚开辟出来的内存区域)
int i = 0;
for (; i < len; i++) {
p[i] = rand() % 100;
}

//手动释放内存
free(p);

动态内存分配与静态内存分配的区别:
    静态内存分配,分配内存的大小是固定的,问题:1、很容易超出栈内存的最大值。2、为了防止内存不够用开辟更多的内存,容易导致内存的浪费
    动态内存分配,在程序的运行过程中,动态制定需要使用的内存大小,手动释放,释放之后,这些内存还能够被重新使用

int len ;
scanf("%d", &len)
int *p = malloc( len * sizeof(int) );
//给数组元素辅助,(使用这一块刚刚开辟出来的内存区域)
int i = 0;
for (; i < len; i++) {
    p[i] = rand() % 100;
}
int addlen;
printf("增加数组的长度:")
scanf("%d", &addlen)
//内存不够用,扩大刚刚分配的内存
//1、原来内存的指针,2、内存扩大之后的总大小
int * p2 = realloc(p, sizeof(int)*(len+addlen) )
//重新分配
//省略

重新分配有两种情况
缩小,缩小的那部分数据丢失
扩大,可能是连续的,也可能不是连续的,如果没有足够空间,申请失败,原来的指针仍然有限

//相比malloc,更加好用
int *p = calloc( lens, sizeof(int) );

内存分配的几个注意细节
1、指针不能多次释放
2、释放完之后,指针要设置为NULL
3、内存泄漏(p重新赋值之后,再free,并没有真正释放内存)

int *p = malloc(1024*1024*10*sizeof(int));
*p = malloc(1024*1024*20*sizeof(int));
free(p)
//第一段内存区域泄露


3、全局区或静态区
4、字符常量区
5、程序代码区

字符串

char str[] = { 's', 'h','t', 't'}
char str[4] = { 's', 'h','t', 't'}
char str[10]= "china";
printf("%s\n", str);
printf("%#x\n", str);       //输出地址

//可以修改
str[0]='s';

字符指针

内存连续排列,不可以修改,类似java中字符串
char *str = "hao are you";
使用指针加法,截取字符串
str += 3;
while (*str) {
    printf("%c", *str);
    str++;
}
    打印 are you


strcpy ()    //赋值内容
strcat()    //字符串拼接
strchr()    //在一个字符串中查找给定字符的第一个匹配字符
strstr()    //从字符串当中查找给定字符串的第一次出现的位置

结构体

结构体是一种构造数据类型
把不同的数据类型整合起来成为一个自定义的数据类型
struct Man{
    char* name;
    int age;
    Int (*func)();
}

//初始化结构体的变量
//1、
strurc Man m1 = {"Jack", 21}
//2、
stuct Man m1;
m1.age = 23;
m1.name = "Rose";

    如果在结构体的定义中,不是char* name;而是char name[20];赋值就应该使用strcpy(m1.name, "Jack")。第一种情况只能在声明的时候赋值,不能够重复赋值
结构体的几种写法
struct Man{
char name[20];
int age;
}m1;        //m1结构体变量名

匿名结构体
//控制结构体变量的个数(限量版),相当于单例
struct {
char name[20];
int age;
}m1;

结构体的嵌套1

struct Teacher{
char name[20];
}

struct Student {
char name[20];
int age;
struct Teacher t;
}

struct Student s1 = new {"javk", 21, {"Jason"}}

结构体的嵌套2

struct Student {
    char name[20];
    int age;
    struct Teacher{
        char name[20];
    }
}

结构体与指针

struct Man{
    char name[20];
    int age;
}
struct Man m1 = {"Javk", 30};
struct Man *p = &m1;

指针与结构体数组

struct Man{
    char name[20];
    int age;
}
struct Man mans[] = { { "Jack", 20 } ,  { "Rose", 20 } }
struct Man* p  = mans;
for (; i < p + 2; i++ ) {}

int i = 0;
for (; i < sizeof(mans)/sizeof(struct Man); i++ ) {}

结构体的大小(字节对齐)
struct Man{
double weight;
int age;
}
打印占位16,
结构体变量的大小,必须是最宽基本数据类型的整数倍

//结构体与动态内存分配
struct Man *p = ( struct Man * )malloc (sizeof (struct Man) * 10);

typedef 类型取别名

1、不同的名称代表在干不同的事情 typedef int jint 
2、不同的情况使用不同的别名

结构体函数指针成员

    struct Girl {
        char * name ;
        int age ;
        //函数指针
        void (*sayHi) (char*);
    }Girl ;
    //Girl结构体指针取别名GirlP
    typedrf Girl* GirlP;    //别名又去取一个别名
    //Girl结构体类似于Java中的类,name和age类似于属性,sayHi类似于方法
    void (*sayHi) (char* text) {
    }

补充:
字符数组赋值,只能在声明时
可以修改内容
重新赋值只能用strcpy()
char a[10] = "Happy";
a[0] = 'f';
strcpy(a, "Sad");

字符指针
char * a = "Happy";
a = "Dad";
不能够修改字符内容

联合体(共用体)

//不同类型的变量共同占用一段内存(相互覆盖),联合变量任何时刻只有一个成员存在,节省内存
//大小:最大的成员所占的字节数
union MyValue {
    int x;
    int y;
    double z;
}
//最后一次赋值有效

枚举

//固定的数据
enum MyEnum {
One ;
Two;
Three;
Four;
Five
}
enum MyEnum e = Three;
//枚举的值,必须是括号中的值
//保证安全性

读取文本文件

char *path = "本地文件地址";
File *file = fopen(path, "r");
if (file == NULL) {
//打开失败
}
//读取
char buff[50];
while (fgets(buff, 50, file)) {
printf("%s", buff);
}
sclose(file);

写入文本文件

char *text = "aaaaaaaaa";
fputs(text, file) ;

//操作二进制文件(计算机的文件存储都是二进制)
//文本文件和二进制之分,其实是一个逻辑之分
//C读写文本文件与二进制文件的差别仅仅体现在回车换行符
//写文本时,没遇到‘\n’,会将其转换成‘\r\n’(回车换行)
//读文本时,没遇到‘\n’,会将其转换成‘\r\n’(回车换行)

char *path = "本地文件地址";
File *read_fp = fopen(path, "rb");
File *write_fp = fopen(path, "wb");
//复制
int buff[50];   //缓冲区域
int len = 0;    //每次读到的数据长度
while ((len = fread(buff,sizeof(int), 50, read_fp))!=0) {
//将读到的内容写入新的文件
fwrite(buff, sizeof(int), len, write_fp);
}
fclose(read_fp);
fclose(write_fp);

获取文件的大小
char *path = "本地文件地址";
File *read_fp = fopen(path, "r");
//SEEK_END定位到文件末尾,0偏移量
fseek(fp, 0, SEEK_END);
//返回当前的文件指针,相当于文件开头的位移量
long filesize = ftell(fp);

C语言执行的流程

编译:形成目标代码(.obj)
连接:将目标代码与C函数库连接合并,形成最终的可执行文件
执行


    预编译(预处理):为编译做准备工作,完成代码文件的替换工作。头文件告诉编译器有这样一个函数,连接器赋值找到这个函数的实现。也方便查找存在这样一个函数。

define指令

//1、定义表示
#ifdef __cplusplus 标识支持C++语法
//防止文件重复引入
//2、定义常数 (便于修改与阅读)
#define MAX 100
//3、定义“宏”
void com_add (int a, int b) {

}
void com_min(int a, int b) {}
#define jni(NAME) add_##NAME(); 参数替换成
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值