Fork me on GitHub

C语言基础

static 存储类

static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。

static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。

指针

指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32 位程序里,所有类型的指针的值都是一个32 位整数,因为32 位程序里内存地址全都是32 位长。指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX 为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?(重点注意)

堆和栈

栈和代码区都是独立存放的,栈是向低地址扩展的数据结构,是一块连续的内存的区域。堆是向高地址扩展的数据结构,是不连续的内存区域。堆和栈不会碰到一起

指针

指针存储的值

指针变量存储的是一个地址,所以不能赋值地址之外的值

1
int *num = 100 //是错误的

1
2
int num = 100;
int* p = #//是对的
  • 取值

    *指针变量名 代表这个指针指向的变量

1
2
3
int num = 100;
int* p = #//是对的
*p = 200;//代表p指针指向的变量(赋值运算)

指针的类型

指针变量的类型决定了通过这个指针找到变量的首地址以后,连续操作多少个字节空间

  • 指针是int* 连续操作4个字节

  • 指针是double* 连续操作8个字节

例:

1
2
3
4
int num = 1000;//11 1110 1000
char *p1 = #
*p1 = 97;//0110 0001
printf("%d\n",num);//num现在为865,二进制为11 0110 0001

1
2
3
4
5
int num1 = 10;
int num = 20;
int* p = #
p++;
printf("%d\n",*p);//打印为10,因为p++,指针已经移动了4个字节,下一个内存存储10正好是4个字节

一维数组的数组名就是数组的地址。不能给数组名赋值,因为数组一旦创建,在内存中就固定了是一个常量,所以不能修改。

索引(中括弧)的本质

  • 指针变量后边可以使用中括弧,在中括弧中写上下标来访问数据
  • p[n];前提是p是一个指针变量。其实等价于*(p+n)

变量地址分配

为变量分配地址的时候,是从高地址向低地址分配

1
2
3
4
5
int num = 10;
int num2 = 20;
int *p1 = #
int *p2 = &num2;
printf(p1>p2) //true

== 指针字符串和数组字符串 ==

1
2
char str1[] = "abcdddd";//存储在栈区
char* str1 = "abcdddd";//存储在常量去,不可修改。str1是常量区的地址

局部变量

  • 指针变量的字符串:指针存储在栈区,字符串是存储在常量区,不可修改

  • 数组变量的字符串:字符串是存储在栈区,可以修改。

全局变量

  • 指针变量的字符串:存储在常量区

  • 数组变量的字符串:字符串是存储在常量区,指针也是存储在常量区。

修改(可变与不可变)

不管是全局还是局部变量指针变量的字符串不可修改,所以要想使用必须通过malloc、memset、msetcpy等操作重新申请一块堆区内存;数组变量的字符串可以修改

数组和字符串

数组

计算数组长度

sizeof(array)/sizeof(array[0])

注意:计算数组的长度只能在定义的代码块中计算,传递后的数组只是一个指针

二位数组

1
2
char[]="abdcd";
char [][10]={"abc","jack","martwin"}//这个数组的每一行是1个长度为10的char一维数组。缺点最大长度不能超过10.

指针数组

1
2
3
4
char *names[4]={"jack","martwin","lily","rose"};//元素的字符串是存储在常量区的。优点:字符长度不限

%p,names[0];//打印出数组中每个元素的指针
%s,names[0];//打印出数组中每个元素

常用函数

  • fputs 将字符串输出到指定流中

    • 标准输入流
    • 文件输入流

    fputs(要输出的字符串,指定的流)

    stdout 标准输出流,即控制台

    1
    2
    char *name = "黑马程序员";
    fputs(name,stdout);
  • fopen 获取文件流

    fopen(文件路径,操作文件的模式)

    操作文件的模式:w->写入;r->读取数据;a->向文件中增加数据

    1
    2
    3
    4
    FILE *pfile = fopen("/Users/wangrifei/Desktop/a.text","w");
    char *name = "FlyOceanFish";
    fputs(name, pfile);
    fclose(pfile);//将文件流关闭!!
  • fgets 从指定流中读取字符串

    • 标准输入流
    • 文件输入流

    fgets(字符数组,接收字符串的长度,流)

stdin:标准输入流,键盘、控制台等

1
2
char input[10];
fgets(input, 10, stdin);
申请在常量区的空间不会被回收,直到程序运行结束

指向函数的指针

1个函数的指针不能任意指向,必须所指向的函数的返回值类型和参数描述必须与指针的描述一样

返回类型 (*指针名)([参数列表])

1
2
void (*pFunction)();//声明了一个没有返回值没有参数的指针函数
int (*pFun)(int num1,int num2);//声明了一个返回值是int型,并且有2个参数的的函数指针
函数的名称就是函数的地址,所以赋值的时候只要将函数的名称赋值给指针函数即可。 注意:函数名称后边不要加小括号,因为加了小括号就是执行了函数

函数指针调用

pFun(1,2)//调用时,可以认为函数指针便是函数名

结构体

  • 声明方法

    struct 名称{};

    1
    2
    3
    4
    struct Student{
    int age;
    char *name;
    };
  • 使用:

    struct 结构体名称 变量名称

    1
    struct Student stu;
  • 初始化

    struct Student stu = {10,”xiaoming”};

    struct Student stu = {10};

    struct Student stu = {.age=10,.name=”xiaoming”};

结构体之间赋值是值传递

结构体数组

为结构体数组某一个元素赋值的时候要强转,告诉赋值的类型,因为’{}’可以代码数组赋值也可以代表struct赋值

1
2
struct Student stus[5];
stus[0]=(struct Student){10,"xiaoming"};//这个地方要强转

数组个数

int len = sizeof(stus)/sizeof(struct Student)

结构体指针

  • 声明

    struct 结构体名* 变量名

    1
    struct Student* pStu = &stu;
  • 访问

    (*结构体变量名).

    结构体指针变量名->

    1
    2
    3
    (*pStu).age = 20;//结构体取值赋值(要用括号括起来)

    pStu->age = 20;//代表把20赋值给pStu指针指向的变量的age成员

宏定义

宏代码是在编译的时候就执行了。

#define 宏名 宏值

static

  • 修饰的变量存储在常量区,函数运行结束不会被回收,static声明的语句只会被执行一次

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void test(){
    static int num = 0;//只会执行一次
    num++;
    print("%d",num);
    }
    int main(int argc, const char * argv[]){
    test();
    test();
    }
    //打印出1,2

C 存储类

  • auto 是局部变量的默认存储类, 限定变量只能在函数内部使用;

  • register 代表了寄存器变量,不在内存中使用;

  • static是全局变量的默认存储类,表示变量在程序生命周期内可见;

  • extern 表示全局变量,即对程序内所有文件可见,(extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候不能修饰局部变量)

参考

0%