IOS之C基础
#include <stdio.h>
int main(int argc, const char * argv[]) {
// insert code here...
printf("Hello, World!
");
return 0;
}
新建但c项目一般都有一个main.c
-
main 是入口文件,一个程序只有一个main
-
include
有2种方式引入文件,<>
or""
,区别在于<>
只查找编译器库函数文件,适用于包含库函数s。""
则首先查找当前目录,没有再查库函数路径,因此适用于自定义文件。 -
大概运行过程
-
C语言的运行分为两大步:编译和链接
- 编译:编译阶段会将对应的xxx.c源文件(ASCII格式)编译成目标文件xxx.obj,它是二进制格式(当然一般我们会有多个.c文件,也就会生成多个对应的.obj);在编译之前要进行预处理(例如#include指令),在编译的同时还要进行语法检查;生成的.obj文件并不能单独执行,因为各个.obj之间是有关联的,而且他们还各自引用了C语言库函数;
- 链接:连接过程就是将各个.obj文件和c语言库函数一起组合生产一个可执行文件都过程
-
.h文件与.c文件
在.c文件中实现对应的函数,在.h中进行函数声明(接口) -
数据类型
-
运算符 常用运算跟js基本一致
-
常用函数
printf
标准输出%d
%u
%o
%x
c%
%s
%f
%e
#include <stdio.h>
int main(int argc, const char * argv[]) {
int a=16;
float b=79.3f;
printf("[a=%4d]
",a);
printf("[a=%-4d]
",a);
printf("[b=%10f]
",b);
printf("[b=%.2f]
",b);
printf("[b=%4.2f]
",b);
return 0;
}
2. `scanf` 接受输入数据
该方法以回车进行结束操作
输入多个参数的时候,分隔符是任意.
#include <stdio.h>
int main(int argc, const char * argv[]) {
int a,b,c;
scanf("%d,%d,%d",&a,&b,&c);//此时需要输入:1,2,3 然后回车
printf("a=%d,b=%d,c=%d
",a,b,c);
return 0;
}
数组和字符串
- 一维数组
int a[2]; a[0] =1 ; a[1] =2 ;
- 多维数组
int a[2][3];//2行3列,二维数组可以看成是一个特殊的一维数组,只是它的每一个元素又是一个一维数组
a[0][0] = 1;
a[0][1] = 2;
a[0][2] = 3;
a[1][0] = 4;
a[1][1] = 5;
a[1][2] = 6;
```
以上面a数组为例,它在内存中的结构如下图
- 字符串
char
类型
//char
char as[] = {'K','e','n','s','h','i','n',' '};
printf("%s
",as);
char bs[] = { 'I', 'a', 'm',' '};
printf("%s
",bs);
char cs[]="YUEYAO";
printf("%s
",cs);
//
char db[2][3]={"Kenshin","Kaoru","Rose","Jack","Tom","Jerry"};
printf("%s
",db);
```
常用函数:
putchar() //一次只能输出一个字符
getchar() //一次只能接收一个字符
puts() //输出单个字符串,不能格式化输出,但会自己添加换行。
scanf() //接收多个输入
gets() //接收一个字符串
strlen() //计算字符长度
指针
直接引用 `int a=1;` 我们想要获取a的值就必须取得a的地址,再到这个地址对应到存储空间拿到a的值。
间接引用 `int a=1;p=a;` 我们想要获取p的值,就必须去p的存储空间拿到p存储内容(这个内容是a的地址),然后根据这个内容在拿到a的值。
int *p;
这个表示法 是指 p变量是一个指针变量
int a=1;
int *p;
p=&a
数组和指针
int a[]={1,2,3};
int *p = &a[0];
如果p指向一个数组,那么p+1指向数组的下一个元素,同时注意p+1移动的长度并不固定,具体需要根据p指向的数据类型而定;
指针可以写成p++形式,但是数组名不可以,因为数组名是常量
不管函数的形参为数组还是指针,实参都可以使用数组名或指针;
函数指针
函数指针定义的形式:返回值类型 (*指针变量名)(形参1,形参2)
char * toUpper(char *a){
char *b=a; //保留最初地址,因为后面的循环会改变字符串最初地址
int len='a'-'A'; //大小写ASCII码差值相等
while (*a!=' ') { //字符是否结束
if(*a>'a'&&*a<'z'){//如果是小写字符
*(a++) -= len; //*a表示数组对应的字符(-32变为小写),a++代表移动到下一个字符
}
}
return b;
}
返回多个指针的函数,只需将指针当做参数传递即可
int operate(int a,int b,int *c){
*c=a-b;
return a+b;
}
函数指针也可以当做函数的参数和返回值
int sum(int a,int b){
return a+b;
}
int sub(int a,int b){
return a-b;
}
//函数指针作为参数进行传递
int operate(int a,int b,int (*p)(int,int)){
return p(a,b);
}
//main
int main(int argc, const char * argv[]) {
int a=1,b=2;
int (*p)(int ,int)=sum;//函数名就是函数首地址,等价于:int (*p)(int,int);p=sum;
int c=p(a,b);
printf("a+b=%d
",c); //结果:a+b=3
//函数作为参数传递
printf("%d
",operate(a, b, sum)); //结果:3
printf("%d
",operate(a, b, sub)); //结果:-1
return 0;
}
预处理
c程序的运行包括 编译 ,链接 2个阶段。
编译之前预处理器首先要进行预处理操作,将处理完产生的一个新的源文件进行编译。
c语言中包括三类预处理指令:
- 宏定义
- 条件编译
- 文件包含
宏定义
程序中经常用到的一些敞亮或者剪短的函数,通常使用宏定义。
定义语句不能用;
结尾
#include <stdio.h>
#define PI 3.14 //宏定义一般大写
#define R 10
#define S 2*PI*R //在另一个宏里面引用了上面的宏
#define SUM(a,b) a+b //定义一个函数 可传参数
#define SUM (a,b) a+b //错误示例!
#undef PI; //强制终止宏定义
条件编译
条件编译其实就是在编译之前预处理器根据预处理指令判断对应条件,如果满足条件就将代码编译进去,否则不进入编译环节。
#include <stdio.h>
#define COUNT 1
int main(int argc, const char * argv[]) {
//判断是否定义了 COUNT 宏
#if defined(COUNT) //等价于:#ifdef COUNT,相反如果判断没有定义过则可以通过#if !defined(COUNT)或者#ifndef COUNT
printf("COUNT defined
");
#endif
//判断宏定义COUNT是否都与1
#if COUNT==1
showMessage("hello,world!
");
#else
say();
#endif
return 0;
}
文件包涵
a.h文件包含b.h,而b.h就不能再包含a.h了,虽然允许但是效率低不推荐。
文件包含 就是用宏定义判断是否存在,再做处理。
person.h
#ifndef _PERSON_H_
#define _PERSON_H_
#include "message.h"
viod say();
#endif
message.h
#ifndef _MESSAGE_H_
#define _MESSAGE_H_
viod showMessage(char *str);
#endif
main.js
#include<stdio.h>
#include"message.h"
#include"person.h"
int main(int argc,const char * argv[]){
showMessage("hello,world
");
say();
return 0;
}
存储方式和作用域
变量作用范围
在C语言中变量从作用范围包括全局变量和局部变量。
int a = 1; //a 全局
init main(nt argc,const char* argvP[]){
int b=2;//b 局部
}
存储方式
存储变量的位置分为:普通内存(静态存储区)、运行时堆栈(动态存储区)、硬件寄存器(动态存储区),当然这几种存储的效率是从低到高的.
根据存储位置的不同在C语言中又可以将变量依次分为:静态变量、自动变量、寄存器变量。
- 静态变量
全局变量、static声明变量都是 静态变量。系统运行过程中只初始化一次。
int a=1; //全局变量在静态内存中。只初始化一次。
void showMessage(){
static int b=1; //同样只初始化一次,第二次调用不会初始化
}
- 自动变量
被关键字
auto
(也可省略)修饰的局部变量 是自动变量,结论是:所有没有被static修饰过的局部变量都是自动变量
int main(ing argc,const char * argv[]){
int a=1;
auto int b=2;
//a b 都是自动变量, auto可省略
//需要注意的是,上面的自动变量是存储在栈中,其实还可以存储到堆中
}
栈一般是程序自动分配,其存储结果类似于数据结构中的栈,先进后出,程序结束时由编译器自动释放;
而堆则是开发人员手动编码分配,如果不进行手动释放就只有等到程序运行完操作系统回收,其存储结构类似于链表。
- 寄存器变量
寄存器变量是在硬件寄存器中。 但存储空间小。 使用
register
修饰的int
或者char
的非静态局部变量 就是寄存器变量。
int main(int argc,const char * argv[]){
register int a=1;
}
- c语言中hi有2中存储类型:常量存储区和代码存储区
分别用于存储字符串常量、使用const修饰的全局变量以及二进制函数代码
可访问性
extern static
- extern作用于变量
extern用于声明一个已经存在的变量,这样一来即使在后面定义一个变量只要前面声明了,也同样可以使用
extern int a;
int main(int argc, const char * argv[]) {
printf("a=%d
",a);
return 0;
}
int a;
- extern作用于函数
extern作用于函数就不再是简单的声明函数了,而是将这个函数作为外部函数
默认情况下所有的函数都是外部函数
- static 作用于变量
static作用于全局变量它的作用就是定义一个只能在当前文件访问的全局变量,相等于私有全局变量
- static作用于函数
static作用于函数则这个函数就是内部函数
static void showMessage(){
}
//其他文件无法使用 showMessage
构造类型
结构体
想要一个变量存储不同的数据类型,就需要用到结构体。
//结构体类型Date
struct Date{
int year;
int month;
int day;
};
struct Person{
char *name;
int age;
struct Date birthday;//一个结构体中使用了另一个结构体类型,结构体类型变量声明前必须加上struct关键字
float height;
};
- 结构体作为函数参数传递的是成员的值(值传递而不是引用传递),对于结构体指针而言可以通过”->”操作符进行访问
枚举
枚举类型是比较简单的一种数据类型,事实上在C语言中枚举类型是作为整形常量进行处理的,通常称为“枚举常量”。
enum Season{ //默认情况下spring=0,summer=1,autumn=2,winter=3
spring,
summer,
autumn,
winter
};
enum Season season=summer; //枚举赋值,等价于season=1
printf("summer=%d
",season); //结果:summer=1
for(season=spring;season<=winter;++season){
printf("element value=%d
",season);
}
共用体
union最终大小由共用体中最大的成员决定,对某一成员赋值可能会覆盖另一个成员。
union Type{
char a;
short int b;
int c;
};