C语言快速入门和相关资料

目录

 

1. 相关资料

2. 快速入门

2.1 数据类型

void万能类型

小结

2.2 变量本质

2.3 内存“四区”

2.4 指针

一级指针

一级指针与字符串

一级指针与数组

二级指针(**)

数组、数组指针,指针数组

多维数组做函数参数 退化的本质 

函数指针

小点:const 强化

小点:define宏定义 

小点:typedef 

​​​​​​​小点:static强化

​​​​​​​小点:extern关键字


1. 相关资料

  • Video
    • C语言基础入门视频学习:链接: https://pan.baidu.com/s/1_-5CdTPXkxtYpbVj3cv_fQ   密码:osfu (备注:视频讲的很清晰,但是时间比较长)
  • 教程:
    • 菜鸟教程:http://www.runoob.com/cprogramming/c-exercise-example1.html  (备注:适合入门)
      • C语言知识点总结:https://wenku.baidu.com/view/75569ee8f8c75fbfc77db254.html  
      • C语言与数据结构精讲: http://c.biancheng.net/cpp/u/shuju/
  • 难点Blogs
    • C语言内存管理:https://blog.csdn.net/lovemysea/article/details/79338678 (备注:注意内存的四个区域及功能)
    • 指针:https://blog.csdn.net/constantin_/article/details/79575638 (备注:需要注意指针的含义,数组与指针的关系)

2. 快速入门

2.1 数据类型

C语言快速入门和相关资料_第1张图片

void万能类型

C语言快速入门和相关资料_第2张图片

小结

C语言快速入门和相关资料_第3张图片

2.2 变量本质

  1. 程序通过变量来申请和命名内存空间 int a = 5
  2. 通过变量名访问内存空间
    1. 一段连续)内存空间的别名(是一个门牌号)
  3. 修改变量有几种方法?
    1. 直接
    2. 间接。内存有地址编号,拿到地址编号也可以修改内存--->指针(编程案例2
  4. 数据类型和变量的关系 ?答案:通过数据类型定义变量
  5. 总结及思考题
    1. 对内存,可读可写
    2. 通过变量往内存读写数据
    3. 不是向变量读写数据,而是向变量所代表的内存空间中写数据。

C语言快速入门和相关资料_第4张图片

2.3 内存“四区”

C语言快速入门和相关资料_第5张图片

C语言快速入门和相关资料_第6张图片

2.4 指针

  • 指针是一种数据类型
  • 指针也是一种变量,占有内存空间,用来保存内存地址
  • *p操作内存
  • 间接赋值(*p)是指针存在的最大意义
  • 引申: 函数调用时,n指针(形参)改变n-1指针(实参)的值。

一级指针

典型用法:做函数参数

  • 一级指针做输入
int showbuf(char *p)
int showArray(int *array, int iNum)
  • 一级指针做输出
int geLen(char *pFileName, int *pfileLen);

理解:主调函数还是被调用函数分配内存;被调用函数是在heap/stack上分配内存

一级指针与字符串

  • C语言中用字符数组模拟字符串
//若没有指定长度,默认不分配零
char buf1[] = {'a', 'b', 'c', 'd', 'e'};

//若指定长度,不够报错;buf长度多于初始化个数,会自动补充零
char buf2[6] = {'a', 'b', 'c', 'd', 'e‘};
char buf3[6] = {'a', 'b', 'c', 'd', 'e‘};
//char buf4[5] = {'a', 'b', 'c', 'd', 'e’};
  • C语言中的字符串是以’\0’结束的字符数组
  • C语言中的字符串可以分配于栈空间,堆空间或者只读存储区

一级指针与数组

 

  • 元素类型角度:数组是相同类型的变量的有序集合 测试指针变量占有内存空间大小
  • 内存角度:连续的一大片内存空间
  • 数组名是数组首元素的起始地址,但并不是数组的起始地址
  • 通过将取地址符&作用于数组名可以得到整个数组的起始地址
  • 数组名 在做函数参数时 退化成指针

二级指针(**)

典型用法(指针做函数参数)

  • 二级指针做输入
int main(int arc ,char *arg[]); 字符串数组
int shouMatrix(int [3][4], int iLine);
  • 二级指针做输出
int Demo64_GetTeacher(Teacher **ppTeacher);

int Demo65_GetTeacher_Free(Teacher **ppTeacher);

int getData(char **data, int *dataLen);

Int getData_Free(void *data);

Int getData_Free2(void **data); //避免野指针

理解: 主调函数还是被调用函数分配内存;被调用函数是在heap/stack上分配内存

数组、数组指针,指针数组

  • 数组
  • 数组指针:指向 数组的 指针  int (*a) [10]
  • 指针数组:指针的数组    int *a[10]

定义数组指针的方式

  • 利用数组类型的别名

 

typedef int (MyArrayType) [5];
MyArrayType *pointer; // a[5]
  • 声明一个数组指针类型
typedef int (*MyPointer) [5];
MyPointer myPoint;
  • 直接定义:
int (*pointer)[n];

多维数组做函数参数 退化的本质 

  • 二维数组可以看做是一维数组
  • 二维数组中的每个元素是一维数组
  • 二维数组参数中第一维的参数可以省略
  • void f(int a[5])   --->  void f(int a[]);   --->   void f(int* a)
  • void g(int a[3][3]) ---> void g(int a[][3]);  ---> void g(int (*a)[3])

函数指针

  • 一个数据变量的内存地址可以存储在相应的指针变量中,函数的首地址也以存储在某个函数指针变量中。这样,我就可以通过这个函数指针变量来调用所指向的函数了。
  • 函数指针变量的声明:
void (*funP)(int) ;   //声明一个指向同样参数、返回值的函数指针变量。

小点:const 强化

  • 修饰普通变量 à常量
  • 指针常量和常量指针
  • 修饰函数参数
    • 防止修改指针指向的内容: void StringCopy(char *strDestination, const char *strSource);
    • 防止修改指针指向的地址: void swap ( int * const p1 , int * const p2 )
  • 修饰函数的返回值:
    • 如果给以“指针传递”方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。
const char * GetString(void);
const char *str = GetString();  //right
// char * = GetString(void); wrong

小点:define宏定义 

参考:https://blog.csdn.net/xingjiarong/article/details/47282255

 

  • 关键字const用来定义常量,如果一个变量被const修饰,那么它的值就不能再被改变,我想一定有人有这样的疑问,C语言中不是有#define吗,干嘛还要用const呢,我想事物的存在一定有它自己的道理,所以说const的存在一定有它的合理性,与预编译指令相比,const修饰符有以下的优点:
    • 预编译指令只是对值进行简单的替换,不能进行类型检查
    • 可以保护被修饰的东西,防止意外修改,增强程序的健壮性
    • 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
  • 预编译指令只是对值进行简单的替换,不能进行类型检查

 

#define MAXTIME 1000
#define max(x,y) (x)>(y)?(x):(y);

小点:typedef 

  • 定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
typedef char* PCHAR;
PCHAR pa, pb;  
  • 用在旧的C代码中,帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名对象名,如:
typedef struct tagPOINT{ int x; int y; } POINT;
POINT p1; 
  • 为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化
    • 原声明:void (*b[10]) (void (*)());
    • 简化:
      • 变量名为b,先替换右边部分括号里的,pFunParam为别名一:
      • typedef void (*pFunParam)();
      • 再替换左边的变量b,pFunx为别名二:
      • typedef void (*pFunx)(pFunParam);
      • 原声明的最简化版:
      • pFunx b[10];

​​​​​​​​​​​​​​小点:static强化

  • 参考:
    • https://www.cnblogs.com/wly603/archive/2012/04/11/2442065.html
    • https://www.cnblogs.com/wly603/archive/2012/04/11/2442065.html
  • static变量定义
    • 局部
      • 静态局部变量在函数内定义,生存期为整个源程序,但作用域与自动变量相同,只能在定义该变量的函数内使用。退出该函数后尽管该变量还继续存在,但不能使用它
      • 对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。
    • 全局
      • 全局变量本身就是静态存储方式静态全局变量当然也是静态存储方式但是他们的作用域,非静态全局 变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。
  • ​​​​​​​​​​​​​​static函数(也叫内部函数
    • ​​​​​​​只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。区别于一般的非静态函数(外部函数) 

​​​​​​​小点:extern关键字

  • extern char *ctime(const time_t *);
  • 具有文件外部链接,但是声明extern变量时,编译器并不会给这个变量分配内存,在另外的文件中定义这个文件时才会为其分配内存,一旦声明了extern关键字,对编译器来意味着:
  • 这个变量声明(即数据类型和变量名,但是编译器并没有分配内存
  • 这个变量的定义在其他文件中(在定义变量的文件中编译器才会为其分配内存)

 

  •  
  •  

你可能感兴趣的:(问题总结,C语言快速入门,C语言学习资料,指针,内存空间详解,数组)