嵌入式软件工程师3--C语言拾遗(1)

C语言拾遗(1)

  • C语言拾遗(1)
    • 细节1
    • 指针
    • 局部变量和全局变量
      • 局部变量
      • 全局变量
      • 跨文件的变量引用
    • 常量
    • 头文件的引入

C语言拾遗(1)

细节1

  1. 一字节为八个二进制位。

  2. strlen:strlen 是一个函数,它用来计算指定字符串 str 的长度,但不包括结束字符(即 null 字符)。

  3. sizeof:sizeof 是一个单目运算符,而不是一个函数。与函数 strlen 不同,它的参数可以是数组、指针、类型、对象、函数等。功能是获得保证能容纳实现所建立的最大对象的字节大小。

  4. 字符数组及它的两种初始化

  1 #include<stdio.h>
  2 int main()
  3 {
  4     char a[] = "abcde"; // 6
  5     char b[] = {'a','b','c','d','e'}; // 5
  6     printf("sizeof(a) = %d,sizeof(b) = %d\n",sizeof(a),sizeof(b));
  7     return 0;
  8 }
  
结果为:sizeof(a) = 6,sizeof(b) = 5

1"abcde"实际上有6个字符,分别为'a','b','c','d','e','\0';
2'\0'这个字符是ASCII码的第一个字符,它的编码值是0'\0'是C语言中定义的字符串的结尾标志。所以当C语言程序中使用"abcde"这种方式初始化时,编译器会自动在字符'e'后面添加一个'\0'。所以变成了6个字符。

## 数据类型
1. 基本类型:char short int long float double
 复合类型:数组 结构体 共用体
 2. 数据类型就好像一个模子,这个模子实例化出C语言的变量。变量存储在内存中,需要占用一定的内存空间。每种数据类型在不同的机器平台上占用内存是不同的。(一般为32位CPU)可用**sizeof**运算符计算得出。
## 有符号数和无符号数
1. 对于char int 等整型类型的数,分为有符号数和无符号数,而对于**floatdouble这种浮点数来说,只有有符号数,没有无符号数。**
2. 变量是存储在内存中的。存储的时候是以二进制方式存储的。对于有符号和无符号数来说,存储方式不同。对于int类型,无符号数:4字节(32位)全部用来存储数的内容;有符号数:32位中最高位用来存符号(**0表示正数,1表示负数**),剩余31位用来存数据。
3. 从绝对数值上来说,无符号数所表示的范围要大一些。
4. 对于float和doule这种浮点类型来说,它们在内存中的存储方式和整型不一样。**绝对不能随意改变一个变量的存取方式。**

## 空类型(void)
1. **C语言中的void类型,代表任意类型,而不是空的意思。任意类型的意思是它的类型是未知的,还没有指定。**
2. 函数的参数列表为void:表示这个函数调用时不需要给它传参数。
3. 函数的返回值为void:表示这个函数不会返回一个有意义的返回值。
4. **void \***:是任意类型的指针。(**绝对不能随意改变一个变量的存取方式。**)存取类型完全有自己负责,编译器不能帮你做类型检查。

指针

  1. 指针全称是指针变量,其实质是C语言的一种变量。这种变量比较特殊,通常他的值会被赋值为某个变量的地址值,然后可以使用*p这样的方式去间接访问p所指向的那个变量。
  2. int *p; 定义指针变量p,在定义时这里的 *含义是告诉编译器p是一个指针变量。
  3. *p = 123;使用指针的时候,*p代表指针变量p所指向的那个变量。
  4. 各种不同的指针
指针变量本质是一个变量,指针变量的类型属于指针类型。

1 int *p;// 定义了一个指针类型的变量p,这个p所指向的那个变量是int型。

1 int a;
2 float *p;
3 p = &a;//warning: assignment from incompatible pointer type

各种指针类型和它所指向的变量类型必须匹配,否则结果不可预知。
  1. 指针与数组的初步结合
数组名:做右值时,数组名表示数组的首元素地址,因此可以直接赋值给指针。
1 int a[5];//a 和 &a[0]都表示数组首元素a[0]的地址,而&a表示数组的首地址。
注意:数组首元素的地址和数组的首地址是不同的。前者是数组元素的地址,后者是数组整体的地址。两个含义不同,但数值上是相同的。
1 int a[];
2 int *p;
3 a = p;
//编译报错,因为数组名是个常量,所以不能赋值,数组名不能做左值。
  1. 函数传参中使用指针
1 int add(int a,int b)
//实际调用该函数时,实参将自己拷贝一份,并将拷贝传递给形参进行运算,实参自己实际是不参与的。所以,在函数中,是没法改变实参本身的。

  1 #include<stdio.h>
  2 
  3 int swap(int a,int b)
  4 {
  5     int t;
  6     t = a;
  7     a = b;
  8     b = t;
  9 }
 10 int main()
 11 {
 12     int a = 2,b = 3;
 13     swap(a,b);
 14     printf("a = %d\n",a);
 15     printf("b = %d\n",b);
 16     return 0;
 17 }
 
  输出:	a = 2
	 	b = 3
 参数是a,b的地址
  1 #include<stdio.h>
  2 
  3 int swap_pointer(int *a,int *b)
  4 {
  5     int t;
  6     t = *a;
  7     *a = *b;
  8     *b = t;
  9 }
 10 int main()
 11 {
 12     int a = 2,b = 3;
 13     swap_pointer(&a,&b);
 14     printf("a = %d\n",a);
 15     printf("b = %d\n",b);
 16     return 0;
 17 }
 
输出:	a = 3
		b = 2

局部变量和全局变量

  1. 定义的同时没有初始化时,局部变量的值是随机的,而全局变量的值默认是0 。
  2. 使用范围上,全局变量具有文件作用域(整个文件),而局部变量只有代码块(在{ }中)作用域
  3. 生命周期上,全局变量是在程序开始运行前的初始化阶段就诞生,到整个程序结束退出的时候才死亡;而局部变量在进入局部变量所在的代码时诞生,在该代码块退出的时候死亡。
  4. 分配位置上,全局变量分配在数据段上,而局部变量在上。
  5. 数据段:存的是数,全局变量存在数据段。代码段:存的是代码,一般是只读的。栈(stack):先进后出,局部变量存在栈中。

局部变量

  1. 被调函数被main函数调用结束,普通的局部变量(auto)的内存就被释放了;静态局部变量(static的内存不释放,和全局变量非常类似。
  2. register(寄存器)类型的局部变量表现上和普通局部变量一样,被称为是C语言中最快变量。C语言会将register变量放到寄存器中运行(普通的变量是在内存中),所以register变量访问速度会很快。但是它是有限制的,因为寄存器数目是有限的,其次register变量在数据类型上有限制,例如不能定义double类型的register变量。一般只在内核或者启动代码中,需要反复使用同一个变量才会使用register变量。

全局变量

  1. 全局变量的定义和初始化是在main函数运行之前发生的。
  2. 普通全局变量可以在各个文件中使用,可以在项目内别的.c文件中被看到,所以要确保变量名不能重名。静态全局变量就是解决重名问题的。它告诉编译器这个变量只在当前本文件内使用,这样就不用担心重名问题。

跨文件的变量引用

  1. 用关键字extern声明一个跨文件变量

常量

  1. #define N 20
  2. const:const和指针结合,有四种形式:
    const int *p:p是一个指针,指针指向一个int型数据。p所指向的数据是个常量。
    int const *p:p是一个指针,指针指向一个int型数据。p所指向的数据是个常量。
    int *const p:p是一个指针,指针指向一个int型数据。p本身是常量,p所指向的数据是个变量。
    const int *const p:p是一个指针,指针指向一个int型数据。p本身是常量,p所指向的数据是个常量。

头文件的引入

  1. #include<>:用来包含系统自带的头文件。
  2. #include“ ”:用来包含当前目录中的头文件。
  3. 防止重复包含头文件
#ifndef _A_H_
#define _A_H_


#endif

你可能感兴趣的:(C语言)