Objective-C和C语言的关系
Objective-C是C语言的严格超集。
任何C语言程序不经修改就可以直接通过Objective-C编译器,在Objective-C中使用C语言代码也是完全合法的。Objective-C被描述为盖在C语言上的薄薄一层,抄因为Objective-C的原意就是在C语言主体上加入面向对象的特性
C介绍
C编译器:gcc编译器
查看gcc编译器版本:gcc -v
C编译过程:
gcc hello.c 生成 hello.out
./hello.out
C 存储类
static
static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。
全局声明的一个 static 变量或方法可以被任何函数或方法调用,只要这些方法出现在跟 static 变量或方法同一个文件中。
extern
extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 extern 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候,如下所示:
第一个文件,main.c
#include <stdio.h>
int count ;
extern void write_extern();
int main()
{
count = 5;
write_extern();
}
第二个文件:support.c
#include <stdio.h>
extern int count;
void write_extern(void)
{
printf("count is %d\n", count);
}
全局变量
全局变量是定义在函数外部,通常是在程序的顶部。全局变量在整个程序生命周期内都是有效的,在任意的函数内部能访问全局变量。
预处理指令
内存管理
内存5区:
计算机中的内存是分区来管理的,程序和程序之间的内存是独立的,不能互相访问,比如QQ和浏览器分别所占的内存区域是不能相互访问的。而每个程序的内存也是分区管理的,一个应用程序所占的内存可以分为很多个区域,我们需要了解的主要有四个区域,通常叫内存四区
代码区
程序被操作系统加载到内存的时候,所有的可执行代码(程序代码指令、常量字符串等)都加载到代码区,这块内存在程序运行期间是不变的。代码区是平行的,里面装的就是一堆指令,在程序运行期间是不能改变的。函数也是代码的一部分,故函数都被放在代码区,包括main函数。
注意:"int a = 0;"语句可拆分成"int a;"和"a = 0",定义变量a的"int a;"语句并不是代码,它在程序编译时就执行了,并没有放到代码区,放到代码区的只有"a = 0"这句。
void test() {
}
void test1() {
}
void (* t1)(void) = test1;
void (* t)(void) = test;
printf("函数test地址=%p 函数test1地址=%p\n\n\n", t, t1);
常量区
c字符串是在常量区的。
printf("字符串xx地址=%p \n", &"abc");
printf("字符串xx地址=%p \n\n\n", &"12342");
// char cStr[2] = "xx"; &cStr[0]是在栈区
静态区
静态区存放程序中所有的全局变量和静态变量。
栈区
栈(stack)是一种先进后出的内存结构,所有的自动变量、函数形参都存储在栈中,这个动作由编译器自动完成,我们写程序时不需要考虑。栈区在程序运行期间是可以随时修改的。当一个自动变量超出其作用域时,自动从栈中弹出。
- 每个线程都有自己专属的栈;
- 栈的最大尺寸固定,超出则引起栈溢出;(线程栈的默认大小是8M)
- 变量离开作用域后栈上的内存会自动释放。
栈是先进后出的,先进入的地址较大。后进入的地址较小。内存溢出后,后入的先被销毁
由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈.
堆区
堆(heap)和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。更重要的是堆是一个大容器,它的容量要远远大于栈。 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
一般比较复杂的数据类型都是放在堆中。但是在C语言中,堆内存空间的申请和释放需要手动通过代码来完成
申请
首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
https://www.cnblogs.com/yif1991/p/5049638.html
https://blog.csdn.net/qianqin_2014/article/details/51114105
局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。
结构体的全局或静态变量也是存在静态区;局部变量在栈区
源文件转换为可执行文件的四步骤
1、预处理(preprocessor):对#include、#define、#ifdef/#endif、#ifndef/#endif等进行处理,删除了注释。 gcc -E a.c a.i
2、编译(compiler):将源码编译为汇编代码 gcc -c a.i a.s
3、汇编(assembler):将汇编代码汇编为目标代码 gcc -s a.s a.o
4、链接(linker):将目标代码链接为可执行文件
指针
通过指针,可以简化一些 C 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。指针是一个变量,其值为另一个变量的地址。在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
算术运算
指针在递增和递减时跳跃的字节数取决于指针所指向变量数据类型长度,比如 int 就是 4 个字节。
指针数组
int *ptr[MAX];
把 ptr 声明为一个数组,由 MAX 个整数指针组成。因此,ptr 中的每个元素,都是一个指向 int 值的指针
指向指针的指针
是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
函数指针
函数指针是指向函数的指针变量。
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数、传递参数。
函数指针变量的声明:
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
int max(int x, int y)
{
return x > y ? x : y;
}
/* p 是函数指针 /
int ( p)(int, int) = & max; // &可以省略
指向结构的指针
struct Books *struct_pointer;
struct_pointer = &Book1;
为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符,如下所示:
truct_pointer->title;
结构体
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;