C语言速成篇

本人最近学习ndk,涉及到C语言,所以写下这篇略显肤浅的笔记…大神请忽略此文…

一、HelloWorld
#include <stdio.h>	 // 包含标准的输入输出的头文件, 类似java的导包
#include <stdlib.h>	 // 包含标准的库函数

main() {	// 入口函数
	   
	   printf("hello World\n"); 
	   system("pause");	  // 调用系统命令,暂停程序,以便查看运行结果 
}
二、数据类型

C语言的数据类型包括基本数据类型、构造类型、指针类型、空类型。其中基本数据类型包括数值类型和字符类型。数值类型又包括整型和浮点类型。基本数据类型如下:

  • char 1字节
  • short 2字节
  • int 4字节
  • float 4字节
  • long 4字节
  • double 8字节

有几个注意事项:

  • C语言中没有byte, 可以用char表示

  • C语言中没有String类型,可以用字符数组或char类型的指针

  • C语言中没有boolean, 可以用整数0表示false, 1表示true

  • signed和unsigned: 数据类型修饰符,用来修饰char, short, int, long 如signed int

  • signed int简称int,signed short简称short,signed long简称long。注意signed char不等于char,这是两种类型了。

  • int32_t 其实就是int , int64_t其实就是long long

  • long long就等于java中的long ,8个字节

      main() {	
         
        long long ago;
         
        // sizeof获取某个数据类型的长度
        printf("char的长度为:%d\n", sizeof(char));
        printf("short的长度为:%d\n", sizeof(short));
        printf("int的长度为:%d\n", sizeof(int));
        printf("float的长度为:%d\n", sizeof(float));
        printf("long的长度为:%d\n", sizeof(long));	// long的长度不会比int短
        printf("double的长度为:%d\n", sizeof(double));
        
        printf("long long的长度为:%d\n", sizeof(long long)); 
        printf("signed int的长度为:%d\n", sizeof(signed int)); 
        printf("unsigned int的长度为:%d\n", sizeof(unsigned int)); 
         
        system("pause");	  
      }
    
三、输入输出
%hd - short
%d  -  int
%ld – long
%c  - char
%f -  float
%lf – double
%u – 无符号数
%x – 十六进制输出  
%#x- 十六进制输出,并输出0x表示十六进制
%o  - 八进制输出   
%#o - 八进制输出,并输出0表示八进制
%s – 字符串 

输入:

int count;
//scanf会报一个不安全的错误,怎么办呢?
//方法一:在引入头文件之前  #define _CRT_SECURE_NO_WARNINGS //宏定义
//方法二:使用新函数scanf_f
scanf_s("%d",&count);//&表示取变量内存地址,把接收的值赋给count
printf("count=%d\n",count);

输出:

char c = 'a';
short s = 1;
int i = -1;
long l = 255;
float f = 3.14;
double d = 3.1415926;

printf("c = %c\n", c);
printf("s = %hd\n", s);
printf("i = %d\n", i);
printf("l = %ld\n", l);
printf("f = %f\n", f);//默认输出6位有效数字
printf("f = %.2f\n", f);// .2 输出两位有效数字 
printf("d = %lf\n", d);  // 默认输出6位有效数字,会四舍五入

printf("i = %u\n", i); // 无符号的数	   
printf("l = %#X\n\n", l); // 十六进制输出 0x
四、指针

指针就是地址,地址就是内存单元的编号;指针变量是存放地址的变量;指针与指针变量是两个概念,但现实中经常把指针变量说成指针。
指针使用中常见错误:
(1)野指针:没有赋值的指针,不能通过*修改对应内存的数据;
(2)数据类型不匹配:比如int类型的指针只能保存int变量的内存地址;

main() {	
	  
	  int i = 100;
	  printf("i的内存地址为:%#x\n", &i);
	  
	  // 定义一个指针变量p,用来保存int变量i的内存地址
	  int* p;  // int *p    int * p;
	  
	  // 把i的内存地址赋值给指针变量p
	  p = &i;
      printf("i的内存地址为:%#x\n", p);
	  
	  printf("i= %d\n", i);
	  printf("i= %d\n", *p);  // *p表示取p保存的内存地址所存放的值,其实就是i的值
	  
	  
	  //区分: p 和 &p 和*p
      printf("%#x\n", p);    // i的内存地址
      printf("%#x\n", &p);   // 指针变量p的内存地址
      printf("%d\n", *p);    // i的值 
      
      system("pause");	  
}
#include <stdio.h>	 
#include <stdlib.h>	 

main() {	
	   
	   int i = 100;
	   
	   int* p = &i;		// 一级指针,保存变量的内存地址
	   int** p2 = &p;	// 二级指针,保存一级指针的内存地址
	   int*** p3 = &p2; // 三级指针,保存二级指针的内存地址
	   
	   printf("i = %d\n", i);
	   printf("i = %d\n", *p);		
	   printf("i = %d\n", **p2);	
	   printf("i = %d\n", ***p3);	
	   
	   system("pause");	  
}

指针的应用:

  • 交换变量值
#include <stdio.h>	 
#include <stdlib.h>	 

/** 交换两个数的值 */
swap1(int i , int j){  // 形参
		 int temp = i;
		 i = j;
		 j = temp;
}

swap2(int* p, int* q){
		int temp = *p;
		*p = *q;
		*q = temp;
}

main() {	
	   
	   int i = 100;
	   int j = 200;  // 实数
	   
	   printf("i = %d\n", i);
	   printf("j = %d\n", j);
	  
	   // swap1(i, j);	   // 不会交换值
	   swap2(&i, &j);	   // 会交换两个数的值
	   	   
	   printf("i = %d\n", i);
	   printf("j = %d\n", j);	   
	   
	   system("pause");	  
}
  • 返回多个值(更改变量值)
#include <stdio.h>	 
#include <stdlib.h>	 

fun(int* p, int* q) {
	  *p =7;
	  *q = 8;
}

main() {   
	   
	   int i =100;
	   int j =200; 
	   
	   printf("i = %d\n", i);
	   printf("j = %d\n", j);
	  
	   fun(&i, &j);
	   
	   printf("i = %d\n", i);
	   printf("j = %d\n", j);	   
	   
	   system("pause");	  
}
  • 主函数中获取子函数变量的内存地址
#include <stdio.h>	 
#include <stdlib.h>	 
fun2(int** q) {
	  int i = 100;
	  printf("i的内存地址为:%#x\n", &i);	  
	  *q = &i;	   
}

main() {	
	   
	   int i = 0;
	   int* p = &i;
	   fun2(&p);
	   
	   // 变量还没来得及被回收,但马上被回收了
	   // printf("i的值为:%d\n", *p);
	   
	   printf("i的内存地址为:%#x\n", p);
	  
	   // 子函数执行完后,局部变量已经被回收
	   printf("i的值为:%d\n", *p);
   
	   system("pause");	  
}

指针与数组:

main() {	
	   
	   // char arr[] = {'a', 'b', 'c'};
	   char arr[] = "Hello";
	   
	   printf("第1个元素的内存地址: %#x\n", &arr[0]);
	   printf("第2个元素的内存地址: %#x\n", &arr[1]);
	   printf("第3个元素的内存地址: %#x\n", &arr[2]);
	   
	   int arr2[] = {1, 2, 3};
	   
	   printf("第1个元素的内存地址: %#x\n", &arr2[0]);
	   printf("第2个元素的内存地址: %#x\n", &arr2[1]);
	   printf("第3个元素的内存地址: %#x\n", &arr2[2]);
	   
	   // C语言中的数组越界了,不会报错
	   printf("第10个元素的值: %d\n\n\n", arr2[9]); 
	   
	   // 数组的首地址: 下面三种方式都是一样的
	   printf("数组的首地址: %#x\n", &arr[0]);
	   printf("数组的首地址: %#x\n", &arr);
	   printf("数组的首地址: %#x\n\n", arr);
	   
	   // 通过指针变量操作数组
	   char* p = arr; 
	   
	   printf("第1个元素的值: %c\n", *p);
	   printf("第2个元素的值: %c\n", *(p+1));  // 往右偏移一个单位, 对于char就是1个字节
	   printf("第3个元素的值: %c\n\n", *(p+2));
	   
	   printf("第1个元素的值: %c\n", p[0]);
	   printf("第2个元素的值: %c\n", p[1]);
	   printf("第3个元素的值: %c\n", p[2]);
	   
	   int* q = arr2; 
	   
	   printf("第1个元素的值: %d\n", *q);
	   printf("第2个元素的值: %d\n", *(q+1)); // 往右偏移一个单位, 对于int就是4个字节
	   printf("第3个元素的值: %d\n\n", *(q+2));
	   
	   // p - q;  // 没有意义
	   	   
	   system("pause");	  
}
五、动态分配内存

栈内存:在栈中分配也叫静态分配;栈内存由系统自动那个分配自动回收;空间大小固定,超出会报栈溢出;速度快。
堆内存:在堆中分配也叫动态分配;堆内存需要调用malloc分配,调用free回收;内存有多大,堆就可以有多大;速度相对慢一些。

#include <stdio.h>	 
#include <stdlib.h>	 
#include <malloc.h>

main() {	
	  
	 int count =  5;
	 
	 // 在堆中创建连续的内存空间
	 int* p = malloc(sizeof(int) * count); 
	 
	 // 对分配出来的内存空间进行赋值
	 int i = 0; 
	 for(; i < count; i++) {
	     // 对每个元素进行赋值
		 printf("第输入第%d个元素:", (i+1)); 	   
         scanf_s("%d", &p[i]); // (p+i)         
	 } 
	 
	 
	 i = 0;  // 输出每一个元素
	 for(; i< count; i++) {
	 	  printf("第%d个元素为:%d\n", (i+1), p[i]); // *(p+i) 
     }
	 
	 // 释放内存
	 free(p);
	 
     printf("第1个元素为:%d\n", p[0]); // 打印第一个元素
	   
     system("pause");	  
}

这里写图片描述

多次调用malloc这个函数分配的空间是不连续的,若要连续,需要用realloc,用法如下:

.......//省略
int* p = malloc(sizeof(int) * count);
// 再次分配内存,与上一次分配出来的内存连续
// 参1: 上一次分配出来的内存空间的首地址
// 参2: 总共要分配多少内存
p = realloc(p, sizeof(int) * (count + newCount));
printf("p = %#x", p);
.......//省略
六、函数指针

函数指针是指向函数的指针变量,本质是一个指针变量,保存函数的内存地址。

#include <stdio.h>	 
#include <stdlib.h>	 

int add(int i , int j) {
	return i+j;
}
main() {	
	   
      // 定义一个函数指针,用来保存函数的首地址
	  int (*pf)(int, int);
	  
	  // 把函数指针进行赋值, 把add函数的首地址赋值给函数指针pf
	  pf = add;
	  
	  // 通过函数指针调用对应的函数
	  int result = pf(3, 5);
	  
	  printf("result = %d\n", result);
	   
	  system("pause");	  
}
七、结构体

结构体的长度不是简单地相加,有一个补齐规则:
(1)结构体的长度并不是所有成员长度相加,在编译时长度会进行补齐以方便位移。
(2)结构体长度补齐规则:
结构体成员的偏移量是成员长度的整数倍, 如果不是则补齐
结构体的总长度是所有成员长度的整数倍,如果不是则补齐;
(3)成员的偏移量即:成员的地址与结构体首地址的差值。

定义方式有三种:

  • 先定义结构体类型,再定义结构体类型变量
struct Student
{
  int age;
  float score;
  char sex;
}

main() {
	struct Student s1; 
}
  • 定义结构体的同时定义结构体类型变量
struct Student2
{
 int age;
 float score;
 char sex;
} s1;

//也可以再定义如下变量:
main() {
    struct Student s2; 
}
  • 直接定义结构体类型变量
struct 
{
 int age;
 float score;
 char sex;
} s1; 

例子:

#include <stdio.h>	 
#include <stdlib.h>	 
void study() {
   printf("good good study...\n");
}


struct Student
{
  int age;		// 4    
  float score;	// 4   
  char sex;		// 1       
  double d;     // 8  
  
  // 定义函数指针
  void (*studyP)();

}


main() {	
	   
      // 结构体初始化
      // 方式1:
	  struct Student s1 = {20, 100, 'f', 0, study};
	  
	  // 方式2:
	  struct Student s2;
	  s2.age = 25;
	  s2.score = 90;
	  s2.sex = 'm';
	  s2.studyP = study; // 函数指针赋值
	  
	  
	  // 访问结构体的成员
	  printf("s1.age = %d\n", s1.age);
	  printf("s1.score = %f\n", s1.score);
	  printf("s1.sex = %c\n\n", s1.sex);
	  	  
	  printf("s2.age = %d\n", s2.age);
	  printf("s2.score = %f\n", s2.score);
	  printf("s2.sex = %c\n\n", s2.sex);
	  
	  // 结构体的长度:
	  printf("结构体的长度: s1 = %d\n", sizeof(s1));//24
	  
	  // 调用函数指针(三种方式)
	  // 方式1:
	  s1.studyP();
	  
	  // 定义结构体指针变量
	  struct Student* p;
	  
	  p = &s1;
	  
	  // 方式2:
	  (*p).studyP();
	  
	  // 方式3
	  p->studyP();  // 转转换成(*p).studyP()
	   
      system("pause");	  
}
八、联合体

当多个数据需要共享内存时可以使用联合体,联合体的成员在赋值时会相互覆盖,因为它们首地址一样。

#include <stdio.h>	 
#include <stdlib.h>	 
union U
{
  float f;  // 4
  int i;    // 4
  char c;   // 1
}


main() {	
	   union U u;
	   u.i = 100;
	   u.c = 'a';
	   
	   printf("u.i = %d\n", u.i); //97
	   
	   printf("联合体的长度: %d\n", sizeof(u));//4
	   
	   system("pause");	  
}
九、关键字typedef
#include <stdio.h>	 
#include <stdlib.h>	 

// 给int起一个别名,叫做jint
typedef int jint;
main() {	   
	   jint aa = 1;
	   printf("aa = %d\n", aa);
	   system("pause");	  
}
  • 31
    点赞
  • 132
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值