【ndk,1】ndk开发,C语言入门讲解

一、C语言helloworld案例入门:

 

#include <stdio.h>  //引入头文件(引入函数库)相当于java import的操作

#include <stdlib.h>

 main()   //主函数,跟java类似 程序的入口函数

{

     printf("Hello world !\n"); //在控制台输出

     system("java cn.itcast.demo.HelloWorld");//调用执行java文件

     system("pause");

}

 

//system("pause");:调用cmd里面的暂停命令,cmd窗口暂停执行以下 ,方便我们观察程序的执行结果.

 

二、C语言的基本数据类型:

 c语言的数据类型

 char, int, float, double, signed,unsigned, long, short and void

 

 1.在c99的语法的中 是没有boolean的数据类型的,true false 非0代表真 0代表的是假.

 2.c语言里面没有byte类型 ,

 如何让c语言表示 java中的byte呢? 可以利用char类型代替java中的byte类型

 

 3.c语言里面没有String的字符串 , c想表示一个字符串 一般是通过char数组来表示的

  sizeof(); 参数是数据类型  返回值就是这个数据类型在内存中占用多少空间

 4. 注意:   signed, unsigned:只能修饰整数类型的数据 不能修饰浮点型的数据。 

          signed表示有符号,unsigned表示无符号。

 

 5.java中的char是两个字节 ,c语言里面 1个字节

*/

#include <stdio.h>   //引入头文件  java import的操作

main()

 {    // %d 代表的是一个占位符 

      printf("char占用的字节为%d\n",sizeof(char));    1个字节

      printf("int占用的字节为%d\n",sizeof(int));      4个字节

      printf("float占用的字节为%d\n",sizeof(float));  4个字节

      printf("double占用的字节为%d\n",sizeof(double)); 8个字节

      printf("short占用的字节为%d\n",sizeof(short));     2个字节

     

      printf("long占用的字节为%d\n",sizeof(long)); 

      printf("signed int占用的字节为%d\n",sizeof(signedint)); 

      printf("unsigned int占用的字节为%d\n",sizeof(unsignedint)); 

       

      //printf("unsigneddouble占用的字节为%d\n",sizeof(unsigned double));  该行代码会报错。

      system("pause");

       

}

三、输入输出函数:

1、C语言中的删除操作使用占位符实现的,不同类型的数据对应不同占位符:

%d  -  int

%ld – long int

%c  - char

%f -  float

%lf – double

%x – 十六进制输出 int 或者long int 或者short int

%o -  八进制输出

%s – 字符串

%hd - short

short

 

2、C语言的输入函数:

Int len;

Scanf(“%d”,&len); //扫描键盘的输入函数:

参数1:输入数据的指定类型的占位符。

餐宿2:指定保存输入数值的变量地址。

 

例:

#include <stdio.h>   //引入头文件  java import的操作

main()

 { 

       int i = 129024;

       long l = 333L;

       char c ='B';

       float f = 3.1415926f;

       double d = 3.1415;

       short s = 257;

       

       printf("int i =%d\n",i);

       printf("int l =%ld\n",l);

       printf("int c =%d\n",c);

       printf("int f =%f\n",f);

       printf("int d =%lf\n",d);

      printf("short s=%hd\n",s);

   

    char cc;

      printf("请输入一个int类型的值\n");

      //& 取地址

     scanf("%c",&cc);

      printf("char cc =%c\n",cc);

//接收输入的字符串:使用char数组:

      //定义一个char类型的数组 叫arr 用来存放字符串

      char arr[]={' ', ' ',' ','',' '};

      printf("请输入一个字符串\n");

       scanf("%s",arr);

     printf("数组的内容%s\n",arr);

      system("pause");

       

}

 

四、指针:

1、所谓指针就是一个地址,地址其实就是一个内存空间的编号.

2、每个变量在内存中都有一个地址 :通过& 符号获取变量的地址.

例:

#include<stdio.h>

main(){

       int i;

       //把i变量在内存中的地址 打印出来

      

       //打印出变量的地址,指针就是一个地址 , 

         //地址为十六进制:如:0xXXXX ,#表示打印的数值前面带0x

        printf("i的地址为%#x\n",&i);

      

        //60秒的倒计时

         for(i =60; i>0;){

                

              printf("剩余时间%d\n",i);                    

              sleep(4000);  

 

              i--;

       }

       

        printf("游戏结束\n");  

        system("pause");     

}

3、指针和指针变量:

例:

#include<stdio.h>

main(){

  // 1. 指针就是地址, 通过一个地址可以访问到一块内存空间, 如果修改这个内存空间里面的内容 

    

     int i = 5;  //定义一个int类型的变量 变量的名字 叫 i 里面存放的内容 是一个int类型的值

  // 2. 指针变量  用来存放一个变量地址的变量

     int* p;    //定义了一个int* 类型的变量 变量的名字叫p 里面存放的内容 是一个

//int* 类型的值

     //也可以定义为:int *p;  或 int * p;

    

     p = &i;  // p里面存放的就是 i变量的地址了.

    

     printf("p的值为%#x\n",p);

   // 指针指针变量的关系 

   // 指针是一个地址 ..

   // 指针变量是存放一个地址的变量 

   //其实是两个完全不同的概念,但是 世面的书籍 习惯上把指针跟指针变量没有做区别

 

     //  * 号操作符的使用

  

     1.使用场景,定义一个指针变量 int*  double* long*

     2.表示两个数据相乘  3*5 = 15;

     3. 如果*号后面跟的是一个指针变量, 用*可以访问指针变量内部存放的地址 里面存储的变量

     

      

      //*p;   //获取p变量里面存放地址所指向的变量,就是i对应的值;

               //*p 和 i 代表的是同一个变量

     printf("*p的值为%d\n",*p);    

    system("pause");     

}

 

五、指针的常见错误:

1、指针未经赋值不能使用:  以下代码会报错:

#include<stdio.h>

main(){

        int i = 5;

        int* p ; 

        printf("*p的值为%d\n",*p);

        system("pause");     

}

2、不同的指针类型 不能进行相互的转化

#include<stdio.h>

/**

不同的指针类型 不能进行相互的转化

每一种变量类型 在内存中占用的空间 是不相同的.

*/

 

main(){

       short s = 278;

       

       int i = 2777777; //4个byte

      

       int* p = &i;

       short* q = &i; // short 在内存空间里面占用的是两个 byte

      

       printf("*p=%d\n",*p);

       printf("*q=%hd\n",*q);

      

      

      

       system("pause");     

}

3、不能使用已经被系统回收掉的内存空间里的数据:

 

 

 

六、案例:交换两个数字.

通过修改地址里面的值 达到了交换数据的目的

 

#include<stdio.h>

void swap2(int* p, int* q){//p代表的是 i的地址, q代表的是 j的地址

 

    // 把i变量和 j变量的地址 传递给了子函数,在子函数里面直接通过修改地址里面的值 达到了交换数据的目的

    // *p 代表的就是 i变量

   

    // *q 代表的就是 j变量

   

    int temp;

    temp = *p;

    *p = *q;

    *q = temp;

    

    

}

//主方法

main(){

  int i = 3;

  int j = 5;    

 // swap(i,j);    

 

  swap2(&i,&j);

  printf("i=%d\n",i);

  printf("j=%d\n",j);

         

  system("pause");     

}

 

七、指针的作用:

1、直接访问硬件 (opengl 显卡绘图)

2、  快速传递数据(指针表示地址)

3、 返回一个以上的值(返回一个数组或者结构体的指针)

 

例:在子函数中同时修改两个变量对应的值:

#include<stdio.h>

 

//相当于是让子函数 修改了主函数里面连个数据的值, 子函数返回一个以上的数据

void f(int* p , int* q){ // p表示的是i的地址, q代表的是 j的地址

    *p = *p+3;

    *q = *q+3;

 

}

main(){

    

     int i = 3;

     int j = 5;

     f(&i,&j); //调用子函数

     printf("i=%d\n",i);

     printf("j=%d\n",j);

     

     system("pause"); 

}

4、 表示复杂的数据结构(结构体)

5、  方便处理字符串

// c语言是没有String类型的 要在c语言里面表示一个字符串 一般都是通过字符数组的方式表示

 

#include<stdio.h>

main(){

   // char arr[]={'h','e','l','l','o'}; 

     

      //char类型的指针变量

     char* arr ="hello";

     //输出字符传

     printf("%s\n",&arr[0]);//arr[0]字符数组的首地址。

      

     system("pause");     

}

 

6 、指针有助于理解面向对象

 

八、指针和数组之间的关系:

1、数组: 

  数组在内存中是一块连续的内存空间。

数组的名称 等于数组中第一个元素的地址(首地址)。

int arr[]={1,2,3,4};

 

printf("arr = %#x \n",arr);

printf("第一个元素的地址为%#x\n",&arr[0]);

上面两行代码输出的值相同。

2、指针操作数组:

 

例:开发一个子方法 把数组的每一个元素都打印出来

#include<stdio.h>

 

// 第一个参数 数组的首地址, 第二个参数 数组的长度

void printArr(int* parr , intlen){

     int i;

     for( i=0;i<len;i++){

//输出方式一:根据数组的下标获取数组中的值:

         printf("arr[%d]=%d\n",i,parr[i]); 

       

      // *parr //数组第一个元素对应的内容

      //*(parr+1) 获取数组第二元素对应的内容(因为内存是连续的空间)

        printf("arr[%d]=%d\n",i,*(parr+i));   

     }

}

 

main(){

        int arr[]={1,2,3,4,5,6,7,8,9};

         printArr(arr,9);

         system("pause");     

}

九、指针的运算:

1、指针的运算只对连续的内存空间才有意义,数组是一块连续的内存空间:

例:数组元素指针之间的运算:

#include<stdio.h>

main(){

    

       //数组是一块连续的内存空间 

       int intarr[] = {1,2,3,4,5,6,7,8,9};

      // int* arr0 = &intarr[0];

      

       int* arr0 = intarr;//数组第一个元素的地址

      

       int* arr1 = &intarr[1];

      

       int* arr2 = &intarr[2];

      

       printf("arr0地址为%#x\n",arr0);

       printf("arr1地址为%#x\n",arr1);

       printf("arr2地址为%#x\n",arr2);

      

     

       printf("arr2与arr0之间的距离为%d\n", arr2 - arr0);

       // 指针的运算 相减和相加得到的结果其实都是 内存地址的偏移量,不是单纯的内存地址整数加减结果.结果代表的有特殊的业务含义, 几个内存空间之间的偏移量.

      

           char chararr[] ={'1','2','3','4','5'};

      // int* arr0 = &intarr[0];

      

       char* chararr0 = chararr;//数组第一个元素的地址

      

       char* chararr1 = &chararr[1];

       

       char* chararr2 = &chararr[2];

      

       printf("chararr0地址为%#x\n",chararr0);

       printf("chararr1地址为%#x\n",chararr1);

       printf("chararr2地址为%#x\n",chararr2);

      

     

       printf("chararr2与chararr0之间的距离为%d\n", chararr2 - chararr0);

      

        system("pause");     

}

九、指针的长度:

#include<stdio.h>

main(){

       //在32位的操作系统上, 2的32次方个内存地址  4个byte

       // 在我当前的32电脑操作系统上 用的devcpp工具, gcc

      

      

       int i =3;

       int* ip = &i;

      

       double d = 3.14159;

       double* dp = &d;

      

      

       float f = 6.28f;

       float* fp = &f;

      

      

       short s = 255;

       short* sp = &s;

      

       //指针的长度都为4。

       printf("int的指针长度为%d\n", sizeof(ip));

      

             

       printf("double的指针长度为%d\n",sizeof(dp));

      

             

       printf("float的指针长度为%d\n",sizeof(fp));

      

             

       printf("short的指针长度为%d\n",sizeof(sp));

      

      

             

        system("pause");     

}

 

十、动态内存和静态内存:

1、动态内存

动态内存创建在堆空间上的   一块不连续的内存空间  可以占用整个操作系统的全部内存

堆内存就是操作系统维护的剩余的内存空间,

在java里面new出来的的所有的对象都是分配在堆内存里面。

在C语言里面,申请堆内存空间使用malloc 函数。

malloc函数接受一个参数 ,参数代表动态的在堆内存申请多大的内存空间.

    malloc的返回值 代表的是申请的这块内存空间的首地址.

 使用free(intp);函数释放堆内存空间,将堆内存标记为可用。

 

 

例:申请堆内存空间:

 

#include<stdio.h>

//引入动态内存分配的头文件

#include<malloc.h>

 

f(int** padress){

       

  //*padress  拿到了主函数里面的p变量    

       

    // 申请一块内存空间 空间的大小为8个字节,空间的首地址把他赋给 intp的变量

    int* intp = (int*)malloc(sizeof(int)*2);      

  

 

   *intp  = 33; // 在堆内存申请的空间里面放置一个int类型的值 值为33

   *(intp+1) = 99; //

  

   *padress = intp;   //把堆内存的地址赋给 主函数里面的p变量

  //free(intp); //释放堆内存空间,将堆内存标记为可用。

  printf("子函数i的地址为%#X\n",intp);

   

}

main(){

    

    int* p ;// 用来存放 子函数里面的i变量的地址

   

    //int -> int*  ->int**

    

    //在主函数里面把子函数的i变量的地址给获取出来  

    f(&p);  

    // 手动的回收掉申请的那块内存空间

    free(p); // 99 内存中的残留的影像,或者幻影

     

    printf("主函数i的地址%#X\n",p);  

    printf("主函数 i的值为%d\n",*p);

     printf("主函数 第二个的值为%d\n",*(p+1));

    system("pause");     

}

 

2、静态内存  创建在栈空间上的  一块连续的内存空间  2M

3、动态内存优点:

动态内存可以跨函数使用,静态函数不可以。

动态内存中数组的长度能在函数运行中动态增加或者缩小

动态的增加数组长度:使用reallco函数。

 

例:动态的增加数组长度:使用reallco函数:

#include<stdio.h>

//引入动态内存分配的头文件

#include<malloc.h>

 

void printArr(int* arr , intlen){

     int i;

     for(i = 0; i<len ;i++){

           printf("学生编号%d的成绩为%d\n",i,arr[i]);

     }

}

main(){

      

        printf("请输入学生的总数\n");

        int len;

        scanf("%d",&len);

    

        //根据len动态的创建一个数组 

    

        int* pgrade =  malloc(sizeof(int)*len);

    

        int i;

        for(i=0;i<len;i++){

          printf("请输入学生%d的成绩\n",i);                

          scanf("%d",(pgrade+i));      

       }

      

       printf("打印学生的成绩列表\n");

    

       printArr(pgrade,len);

      

      

       printf("请输入增加学生的个数\n");

      int addnumber;

       scanf("%d",&addnumber);

      

       pgrade = realloc(pgrade,sizeof(int)*(len+addnumber));

       int j;

       for(j=len;j<(len+addnumber);j++){

            printf("请输入新添加的学生%d的成绩\n",j);                

          scanf("%d",(pgrade+j));                                                           

       }

        printf("重新打印学生的成绩列表\n");

    

       printArr(pgrade,len+addnumber);

       system("pause");     

}

 

十一、堆和栈的区别:

1.申请方式

栈:   

由系统自动分配.例如,声明一个局部变量int  b; 系统自动在栈中为b开辟空间.例如当在调用涵数时,需要保存的变量,最明显的是在递归调用时,要系统自动分配一个栈的空间,后进先出的,而后又由系统释放这个空间. 

堆:   

需要程序员自己申请,并指明大小,在c中用malloc函数   

如char* p1  =  (char  *)malloc(10);   

但是注意p1本身是在栈中的.

  2  申请后系统的响应   

 栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。   

堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,    会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。   

 

3.申请大小的限制   

栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(vc编译选项中可以设置,其实就是一个STACK参数,缺省2M),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。   

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。   

 

 4.申请效率的比较:   

栈:由系统自动分配,速度较快。但程序员是无法控制的。   

堆:由malloc/new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.   

 

 5.堆和栈中的存储内容   

栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。   

当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。   

堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。   

 

6.内存的回收

栈上分配的内存,编译器会自动收回;堆上分配的内存,要通过free来显式地收回,否则会造成内存泄漏。

  堆和栈的区别可以用如下的比喻来看出:   

使用栈就像我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。   

使用堆就像是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

 

十二、java的值传递和引用传递:

public StringgetPersonName(Person p){

    return person.getName();

}

 

p变量里面存放的是一个 堆内存里面person对象的地址. (值). // 感觉java是只有值传递。

 

p变量他代表的是person对象的一个引用, 引用传递.

 

十三、多级指针:

例:使用r取到i的值:

#include<stdio.h>

 

main(){

      

       int i = 3;

       int* p = &i;

      

       int** q = &p;

      

      

       int*** r = &q;

      

       //取到i 的值

       printf("i=%d\n",***r);

      

      

      

       system("pause");     

}

十三、函数的指针:

获取函数的首地址,通过首地址,就可执行该函数。

 

例:

#include<stdio.h>

/**

1.定义int (*pf)(int x, int y); 

2.赋值 pf = add;

3.引用 pf(3,5);

*/

 

int add(int x, int y){

   

    return x+y;

}

 

main(){

      int (*pf)(int x,int y); // 定义一个函数的指针指针的类型是返回值为int 接受的参数 int 

      pf =add;

      printf("result=%d\n",  pf(3,6));

      system("pause");     

}

 

十四、结构体:使用struct 定义结构体:

 

#include<stdio.h>

//定义一个结构体

struct Student

{

    char sex; //1

    int age; //4

    float score; //4

    int id; //4

};

 

main(){

//

    struct Student st={80,55.6f,10000,'F' };

   

    //获取结构体的指针

    struct Student* pst = &st;  

   

    printf("age=%d\n",st.age); 

      

     //结构体的长度

    printf("结构体的长度%d\n",sizeof(st));

   

    //通过指针获取结构体中的变量

    printf("age=%d\n", (*pst).age);

    //通过指针获取结构体中的变量 的第二种写法:

    printf("age=%d\n", pst->age);

    system("pause");      

}

 

十四、联合体:

// 联合体的作用是声明一块公用的内存空间,长度跟公用的数据类型中最长的一个条目一致,

当多次为同一个联合体赋值时,会覆盖:

 

 

#include <stdio.h>

 

main( )

 {

     

      struct date { int year, month, day;}today;

       union { long i; int k; char ii; } mix;

 

// 联合体的作用是声明一块公用的内存空间

// 长度跟公用的数据类型中最长的一个条目一致

      printf("date:%d\n",sizeof(struct date));

 

       printf("mix:%d\n",sizeof(mix));

        //下面的赋值,先定义的会被覆盖。

        mix.i = 99;

        mix.k = 18;

        mix.ii = 'A';

        printf("i=%ld",mix.i);

       

        system("pause");

}

十五、枚举:

#include <stdio.h>

enum WeekDay

{

Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday

};

 

int main(void)

{

  //int day;

  enum WeekDay day = Sunday;

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

 

  system("pause");

  }

 

十六、typedef:

声明自定义数据类型,配合各种原有数据类型来达到简化编程的目的的类型定义关键字。

typedef int  haha;//声明一个int型的数据类型

 

例:

#include <stdio.h>

typedef int  haha;

int main(void)

  haha i = 3;

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

 

  system("pause");

 

  return 0;

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值