C语言的基础知识,主要是为jni做准备,最终是NDK开发,如音视频处理等,后期还会继续更新一些C++的知识点。

数据类型

  1. 占位符:
数据类型 占位符 字节数
%f float
%d int,short 4
%ld long
%lf double
%c char 1
%x 十六进制
%o 八进制
%s 字符串

sizeof(int)查看数据类型占用字节数

2.getchar()等待输入,类似system(“pause”)

C的标准写法

不同平台的c语言写法不一样,需要标准写法:

1
2
3
4
5
6
7
8
#include <stdio.h>
// 标准写法:
int main(int argc,char* argv){
int i = 0;
for(;i < 5 ;i++){
printf("%d\n",i);
}
}

1
2
3
4
5
6
7
#include <stdio.h>
// 一般window下c的习惯写法
int main(){
for(int i = 0; i < 5; i++){
printf("%d\n",i);
}
}

输入输出函数:

1
2
3
4
5
6
7
8
9
10
#define _CRT_SECURE_NO_WARNINGS// 宏定义,不会做安全检查
#include <stdio.h>
#include <stdlib.h>
void main(){
int i;
// 赋值,&i代表取i的地址
scanf("%d",&i);
// 打印
printf("输入的值为%d",i)
}

指针

指针存储的是变量的内存地址;

1
2
3
4
5
6
7
8
void main(){
int i = 0;
int* p = &i; // p的值就是i这个变量的内存地址
printf("%#x\n",p); // 地址值都是十六进制的。#x为输出格式
i = 200; // 间接赋值
*p = 400; // 对p存的变量进行操作
system("pause");
}

  1. 指针必须赋值,如int *p = NULL;地址值为0;不能取空指针的值。不能给指针直接赋值为p=1,10,100等,操作系统不允许访问。
  2. 指针的运算:
    一般在数组遍历时才有意义,数组呈线性排列。
    int *p = xxx;
    p++表示向前移动sizeof(数据类型)个字节;如:
    1
    2
    3
    4
    5
    void main(){
    int arr[] = {1,2,3,4,5,80};
    int *p = arr; // arr = &arr = p三者一样
    printf("%d",*p); // 结果为1,因为数组的地址值为数组第一个元素的地址值,当执行p++,则结果为2,
    }

函数指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
void msg(char* msg,char* title){
MessageBox(0, msg,title,0);
}
int main(int argc, const char * argv[]){
//msg()
// 函数指针
void(*fun_p)(char* msg,char* title) = msg;
// 调用函数指针
fun_p("111","222");
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int add (int a, int b){
return a + b;
}
int sub (int a, int b){
return a - b;
}
typedef int(*fun_p)(int a, int b);
void msg(int (*fun_p)(int a, int b),int m, int n){
// 类似于java的回调函数
int r = fun_p(m, n);
printf("%d\n", r);
}
void main(){
// int(*fun_p)(int a,int b) = add;
msg(add,10,20);
msg(sub,60,50);
}
1
2
3
4
5
6
7
8
9
10
int* getMinPointer(int ids[], int len){
int i = 0;
int* p = &ids[0]
for(; i < len; i++){
if(ids[i] < *p){
p = &ids[i];
}
}
return p;
}

动态内存分配

内存泄漏:当指针赋值之后再free,并没有真正释放内存

1
2
3
4
5
6
7
8
9
10
11
12
13
void main(){
// 40m
int* p1 = malloc(1024 * 1024 * 10 * sizeof(int);
// 这里要对p1进行释放,不释放则造成内存泄漏
free(p1);
p1 = NULL;
p1 = malloc(1024 * 1024 * 10 * 2);
if(p1 != NULL){
free(p1);
p1 = NULL;
}
getchar()
}

字符串

  1. 使用字符数组存储字符串,可以修改(类似java的StringBuffer),几种写法:
    char str[] = {‘c’,’h’,’\0’};
    char str[2] = {‘c’,’h’};
    char str[10] = “ch”;
    str[0] = ‘s’;
  2. 字符指针,不可修改(类似java的String): char *str = “how are you?”;
  3. 字符串api学习网址
  4. 字符数组赋值,只能在声明时:
    char a[10] = "happy" // 可以,不能又a="sad"
    但是字符数字可以修改内容,比如a[0] = ‘H’;
    重新赋值只能用strcpy;
    字符指针可以不在声明时赋值,但是不能修改内容,同上第一条。
  5. demo:查找一个字符在字符串中的索引值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void main(void) {
    char *str = "I am a coder!";
    printf("字符串首地址为%#x\n",str);
    // 也是0元素的指针
    // strchr在一个串中查找给定字符第一个匹配之处
    char* p = strchr(str, 'a');
    if(p){
    printf("索引位置%d\n",p - str);
    }else {
    printf("没有找到")
    }
    system("pause");
    // 结果为2
    }

结构体

结构体的几种写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Man{
char name[20];
char* sex;
int age;
}m1,m2 = {"jian","m",26}; // m1是结构体变量名。
typedef int Age; // 别名
void main(){
Age a = 9;
m1.sex = f;
strcpy(m1.name,"jack");
m1.age = 10;
m2.age = 20;
}

匿名结构体
主要是控制结构体个数。

1
2
3
4
struct{
char name[20];
int age;
}m1,m2;

联合体(共用体)

  1. 联合体是不同类型的变量共用同一段内存,相互覆盖,联合变量任何时刻只有一个成员变量,节省内存。联合体的带下=最大成员所占的子节数。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    union MyValue{
    int x;
    int y;
    double z;
    }
    void main{
    union MyValue d1;
    d1.x = 1;
    d1.y = 2;
    d1.z = 2.3;
    // 最后一次赋值的有效
    }

枚举

枚举是一种数据类型,默认递增

1
2
3
4
5
enum Day{
Monday,
Tuesday,
Sunday
};

相当于

1
2
3
4
5
enum Day{
Monday = 0,
Tuesday = 1,
Sunday = 2
};

这是默认情况,也可以自己写固定的数。

1
2
3
4
5
6
7
8
enum Day d = Monday;
enum Day *p = &d;
int i = 0;
for(; i < 3; i++){
printf(%d\n,*p);
p++;
}
// 输出结果看不懂,说明枚举的变量在内存上不是连续的。

I/O

api帮助文档

  1. I:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 读取文本文件
    void main{
    char path[] = "E:\\xxx\\xxx\\xxx.txt";
    // 1.打开
    FILE *fp = fopen(path,"r"); //rb,wb(binary)代表操作二进制文件
    if(fp == NULL){
    printf("文件不存在");
    return;
    }
    // 2.读取
    char buff[50]; // 缓冲区域
    while(fgets(buff,50,fp)){
    printf("%s",buff);
    }
    // 3.关闭
    fclose(fp);
    getchar;
    }
  2. O:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char path[] = "E:\\xxx\\xxx\\xxx.txt";
    // 1.打开
    FILE *fp = fopen(path,"w");
    char* text = "学java\r\n真是太好啦";
    if(fp == NULL){
    printf("文件不存在");
    return;
    }
    // 2.写入
    fput(text,fp);
    // 3.关闭
    fclose(fp);
  3. I/O:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char* r_path = "E:\\xxx\\xxx\\read.txt";
    char* w_path = "E:\\xxx\\xxx\\write.txt";
    FILE *r_fp = fopen(r_path,"rb");
    FILE *w_fp = fopen(w_path,"wb");
    // 复制
    int buff[50]; // 缓冲区域
    int len = 0;
    while((len = fread(buff,sizeof(int),50,r_fp)) != 0){
    fwrite(buff,sizeof(int),len,w_fp);
    }
    // 关闭流
    fclose(r_fp);
    fclose(w_fp);
  4. 获取文件大小
    // 0代表偏移量,seek_end代表文件末尾
    fseek(fp,0,SEEK_END);
    // 返回当前文件指针,相当雨文件开头的位移量
    long filesize = ftell(fp)

宏定义define

宏替换,为了使用更方便。