使用 Xcode 初始化一个 c 语言项目
- 打开 Xcode 选择"create a new Xcode project"
- 选择 macos/Command Line Tool, 然后点击 next
- 填写 product name(项目名 HelloWorld)、Organization Identifier(组织认证 cn.hifelix.ios)、选择 language 为"C"
- 在 main.c 中书写一下内容
#include <stdio.h>
int main () {
printf("This is my first Xcode C project! \n");
return 0;
}
Xcode 两个常用的快捷键
- command + R 自动编译并执行
- conmand + B 自动编译(检查错误)
为 Project 添加多个 Target
常见的数据类型
int float double char
int(整型) -2147483648 ~ +2147483647
float(单精度浮点型) 有效位数不超过 7 位数的小数(超过 7 位无法精确保存, 前面 7 位可以精确保存)
double(双精度浮点型) 有效位数不超过 16 位数的小数(超过 16 位无法精确保存, 前面 7 位可以精确保存)
char(字符型) 字符类型
变量的声明
int a;
变量的赋值
int 型
int num;
num = 100;
float 型
为 float 类型变量赋值
· 在 C 语言中, 直接写一个小数, 那么这个小数的数据类型是 double 类型的
· float 只能精确保存有效位数不超过 7 位的小数, 超出的部分不会精确保存
float f1;
f1 = 12.12f(如果写 12.12 那就是 double 类型)
double 型
double a;
a = 12.12
char 型
· char 变量中只能存储单个字符, 并且单个字符还要用单引号引起来
· 如果字符给的太多, 保存最后一个
· 空格也是一个字符, 所以可以保存一个空格
· char 变量无法储存中文(一个中文占 3 个字节, 一个 char 变量占一个字节)
char ch;
ch = 'a';
输出变量的值
· printf("输出信息");
双引号中的内容原样输出
· printf("格式控制字符串", 变量列表)
输出的变量类型不同, 占位符号不同
int a;
a = 18;
print("变量 a 的值是%d", a);
占位符
%f --- float 类型占位符(默认输出小数点后面 6 位)
%d --- int 类型占位符(默认输出小数点后面 6 位)
%lf --- double 类型占位符
%c --- char 类型占位符
一次输出多个变量的值
int a = 10;
float b = 10.12f;
printf("int a 的值是%d, float b 的值是%f", a, b);
声明多个变量
int a, b, c, d;
int a = 1, b = 2, c = 3, d = 4;
变量的命名规则
· 变量名只能以任意的字母, 下划线, $开头, 不能以数字开头
· 后面可以跟字母, 数字, 下划线, $开头
· 不能使用 C 语言的关键字
· C 语言严格区分大小写
scanf 函数的使用
语法格式:
scanf("格式控制符", 变量地址列表);
使用 scanf 函数接收输入其他类型的数据
想要用户输入什么类型的数据, 是根据格式控制符中的占位符来决定的
%d 用户输入 int 类型的数据
%f 用户输入 float 类型的数据
%lf 用户输入 double 类型的数据
%c 用户输入 char 类型的数据
- 先声明 1 个变量, 变量的类型要和用户输入的数据的类型一致
- 使用 scanf 函数让用户输入数据
a. 在格式控制符中协商对应的占位符, 一定要对应的
b. 要将用户输入的数据储存到哪个变量中, 就把变量的地址写在后面, 使用就可以取到变量地址
int main () {
float f1 = 0.01f;
scanf("%f", f1);
}
- 使用 scanf 函数接收用户输入多个数据
a.在格式控制符中写上多个占位符就可以了, 有多少个占位符就代表要让用户输入多少个数据, 占位符是什么类型就代表用户输入的数据的类型
b.在后面一次写上储存用户输入的数据的变量的地址
c.用户在输入数的时候, 可以使用空格或者回车来分割多个数据
清空缓冲区中的数据
rewind(stdin);
算数运算符
算数表达式的结果的类型
a.两个相同类型的操作数操作后的结果的类型是这两个操作数的类型;
b.两个不同类型的操作数的类型不一致, 那个么结果就是精度较大的那个类型 int < float < double
自增/自减表达式
前自增/自减表达式的结果是自增/自减后的结果, 后自增/自减表达式的结果是变量自身,然后再进行自增/自减操作
布尔值
C 语言中, 使用 int 来表示布尔值, 0 表示 true, 非 0(1) 表示 false
逻辑表达式
&& 与
|| 或
! 非
格式化代码快捷键(ctrl + i)
变量的作用域
大括号中的变量在大括号中的代码自行完毕以后就会被回收掉
C 语言产生随机数的方法
先引入一个系统头文件
inclde <stdlib.h>
- 调用 arc4random 函数
在其中传入一个整数 n, 就会返回 0~(n - 1)的随机数
int num = arc4random(10);
就会产生 0-9 的随机数, 并赋值给 num
switch case 语法注意事项
switch(表达式)
{
case: 1:
printf("这是 case1");
break;
case: 2:
{
int a = 1;
printf("int a 的值是 %d", a)
}
}
goto 语句(可以实现循环)
语法: loop 为标识符, 可以自己命名
注意: 标识符下面的一句代码, 不能声明变量(C 语言中, 不能在标识符后面声明变量);
int main () {
loop:
print("Mr Chan");
print("Mr Feng");
print("Me");
goto loog;
}
函数的使用
注意: 函数需要定义在 main 方法外面, 要不然会报错!
函数的声明
void test(); # 函数的声明(相当于变量提升)
int main () {
test();
}
void test() { # 函数的定义
printf("这里是函数的定义");
}
预处理指令
C 语言的代码主要分为两类:
1) c 代码
2) 预处理代码
# 开头的, 比如 #include <stdio.h>
预处理指令的分类
文件包含指令 #include
宏定义 #define
条件编译指令 #if
文件包含指令
作用: 可以将指定的文件内容拷贝到指定的地方
语法:
#include "文件路径"
#include <文件路径>
两种语法的区别:
使用"", 先去当前源文件所在的目录中去查找这个文件, 如果有的话就直接包含, 如果没有的话就去系统自带的编 译器目录中查找, 如果有就包含, 没有就报错
使用<>包含, 直接去系统自带的编译器目录中查找, 如果有就包含, 没有就报错
使用: #include "/User/HiFelix/Desktop/1.txt" (会将 1.txt 中的代码复制到本文家中)
C 语言中的四种进制
二进制
写法(在数字前面加上 0b), 例如: int num = 0b10001010101010;
八进制
写法(在数字最前面加上 0): 例如: int num = 0133;
十进制
十六进制
写法(在数字前面加上 0x), 例如: int num = 0x167acde;
输出
%d 将整型变量中的数据以十进制输出;
%o 将整型变量中的数据以八进制输出;
%x 将整型变量中的数据以八进制输出;
变量的内存大小
int 4 个字节
double 8 个字节
float 4 个字节
char 1 个字节
位运算
1.按位与运算 &
2.按位或运算 |
3.按位取反 ~3
4.按位异或 3^2(相同为 0, 不同为 1)
5.按位左右或右移 << >>
int 类型修饰符
short 修饰符
short int num = 10, 让 int 只占用两个字节,最大可以表示 2 的 15 次方的数
short int 变量输出占位符 %hd
short int 变量的声明可以省略 int, 例如: short num = 10;
long 修饰符
在 32 位的操作系统中 long 修饰符占 4 个字节
在 64 位的操作系统中 long 修饰符占 8 个字节
long int 变量输出占位符 %ld
long long 修饰符
long long int 变量输出占位符 %lld
无论是 32 位的操作系统还是 64 位的操作系统中 long long 修饰符都占 8 个字节
unsigned 修饰符
表示这个数的最高位不用来表示符号 unsigned int num = num
unsigned int 变量输出占位符 %u
unsigned short 变量输出占位符 %hu
unsigned long 变量输出占位符 %lu
unsigned long long 变量输出占位符 %llu
数组
a.1 个数组中呢个储存类型相同的多个数据, 是我们创建的时候指定的
b. 数组可以存储的数据的个数是固定的, 是我们创建的时候指定的
数组的声明
int arr[4] --> 创建一个可以存 4 个 int 的变量名为 arr 的数组
往数组中存数据
arr[1] = 100
数组的初始化(只初始化一个值的话, 其他的值会被初始化为 0)
int arr[3] = { 10, 20, 30 }
int arr[] = { 10, 20, 30, 40, 50}
int arr[3] = { [1] = 10, [2] = 20 }
计算数组的长度
int lenth = sizeof(arr) / sizeof(int);
二维数组
二维数组的声明
int arr3 (声明一个 3 行四列的数组);
二维数组的赋值
arr1 = 100;
二维数组的初始化
- int arr3 = {
{1, 23, 44},
{2, 22, 11},
{12. 45, 75},
{223. 99, 64},
} - 行数可以省略, 例如
int arr[][4] = {
{1, 23, 44},
{2, 22, 11},
{12. 45, 75},
{223. 99, 64},
} - 省略里面的大括号
int arr3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} - 部分初始化(第一个一维数组的第一个元素初始化为 10, 第二个一维数组的第一个元素初始化为 10, 第三个一维数组的第一个元素初始化为 10, 其他的都初始化为 0)
int arr3 = {{10}, {20}, {30}} - 部分初始化(按照顺序初始化, 其余的都会初始化为 0)
int arr3 = {1, 2, 3, 4} - 字符数组的初始化(如果只初始化了部分元素, 那么其他字符会被初始化为\0, \0 是一个不可见元素, 打印出来什么都没有, \0 这个字符 ASCII 码是 0)
chat chr[4] = { 'a' };
字符串数据(c 语言中, 字符串数组必须要用双引号引起来)
字符串数组的声明
- char name[] = { 'j', 'a', 'c', 'k', '\0' }
- char name[] = { "jack" } # 后面会自动加\0
- 最常用的方式 char name[] = "jack";
- char name[10] = "jack"; 后面会有 5 个\0
- 一个中文占用 3 个字节
字符串数组的输出
格式控制符%s
原理: 从指定的字符串数组地址开始从低字节向高字节一个字节一个字节的输出, 知道遇到\0 结束
字符串数组的长度
需要使用 while 循环
int len = 0;
while (name[len] != '\0') { len++ };
循环结束后即可拿到字符串的长度
字符串常用函数
-----------------------这两个函数是在 stdio.h 文件中的, 可以直接使用----------------------------
- puts()函数
作用: 用来输出字符串的
语法格式: puts(字符串数组名)
优点: 输出完毕之后, 自动换行
缺点: 只能输出字符串, 也不能使用占位符 - get()函数
作用: 从控制台接收用户输入 1 个字符串数据
语法格式: gets(字符串数组名)
优点: 当用户输入的数据包含空格的时候, 它会连空格一起接收
缺点: 和 scanf 函数一样, 不安全(当用来储存字符串的数据的字符串数组长度不够的时候, 程序会崩溃)
-----------------------下面这四个函数, 是声明在 string.h 这个头文件中的----------------------------
- strlen()函数(返回值类型为 unsigned long 类型)
作用: 得到储存在字符数组中字符串数据的长度 - strcmp() 函数
char name1[] = "jack";
char name2[] = "rose";
strcmp(name1, name2);
比较两个字符串大小(比价首字符大小, 如果首字符一样, 就往后比较)
返回值是 int 类型, 大于 0, name1 大, 等于 0, 一样大, 小于 0, name2 大 - strcpy
char name1[] = "jack";
char name2[] = "rose";
strcpy(name1, name2);
将 name2 的值拷贝到 name1 中
6.strcat() 字符串数据拼接
清除打印信息 --> system(“clear”);
指针(指针就是变量的地址)
指针变量
指针变量的声明
int p1;(声明了一个类型为 int/int 指针类型的变量名为 p1 的指针变量)
也可以写成: int p1; int p1;
批量声明: int p1, p2, *p3;
指针变量的初始化
int num = 100;
int* p1 = #
如果不为指针变量初始化一个地址, 至少为指针变量初始化一个NULL或者0值, 以免造成野指针指向不明导致程序出现bug
int p1 = null; int p1 = 0;
指针变量的使用
p1 = 100; (p1)就指向num;
内存中的五大区域(不管是哪个区域, 都是用来存数据的)
栈区、堆区、BSS段、数据段/常量区、代码段
栈区
用来存储局部变量
堆区
允许程序员手动得从堆区申请空间来使用
BSS段
用来存储未初始化的全局变量和静态变量
数据段
用来存储已经初始化的全局变量、静态变量、常量数据
代码段
用来存储程序的代码/指令
使用fputs将字符串数据输出到指定的流中
流: 标准输出流 --> 控制台
char *name = "陈峰";
fputs(name, stdout);
文件流 --> 磁盘上的文件
1) 声明一个指针文件, 指向磁盘上的文件
fopen函数可以创建一个指向文件的指针
fopen函数的两个参数
第一个参数: 文件的路径, 代表创建的指针指向这个文件
第二个参数: 操作这个文件的模式(w: write, r: read, a: append)
2) 使用fputs将字符串写入到指定的文件当中
fputs(字符串, 文件指针);
3) 写完之后, 一定要记得使用fclose()将这个文件关闭
使用fgets从指定的流中获取内容
fgets(name, 10, stdin);
malloc函数 / calloc函数 / realloc函数
这三个函数的声明都是在stdlib.h的系统头文件中
malloc函数
int *p1 = malloc(4);
作用: 向对空间申请指定字节的空间来使用
参数: size_t(unsigned long)
返回值: void *, 代表没有类型的指针
释放空间 free(指针);
calloc函数
相比于malloc的优势
1) 可以传入sizeof(int)来指定空间大小
2) 空间的垃圾值会被初始化
int *p1 = calloc(4, sizeof(int));
relloc函数(扩容)
指向函数的指针
1) 一个指向函数的指针, 并不是任意的函数都可以指向的
2) 语法
返回值类型 (*指针名)([参数列表])
void (*pFuction)();
表示声明了一个指向函数的指针, 名字叫做pFunction
这个指针只能指向没有返回值, 并且没有参数的函数
int (*pFun)(int num1, int num2);
3) 初始化
void test () {}
void (*pFunc)() = test;
4) 调用
pFunc();
或者(*pFunc)();
结构体
语法格式:
struct 新类型名称
{
// 在这里写上你创建的新类型是由那些变量联合而成的
数据类型1 小变量名称1
数据类型2 小变量名称2
数据类型3 小变量名称3
}
示例
struct Student
{
char *name
int age
int score
float height
}
声明结构体类型的变量
语法格式
struct 新类型名称 变量名;
struct Student stu;
结构体变量的初始化
第一种初始化的方式:
stu.name = "felix";
stu.age = 18;
stu.score = 95;
stu.height = 180;
第二种初始化的方式:
struct Student stu = { "felix", 18, 95, 180 };
第三种初始化的方式(指定成员的初始化):
struct Student stu = { .name = "felix", .age = 18, .score = 95, .height = 180 };
宏定义
语法
#define 宏名, 宏值
#define N 10;
使用
int a = N + 1;
条件编译指令
语法
if N > 0
printf("呵呵")
elif N > 0
printf("呵呵")
else N > 0
printf("呵呵")
endif
ifdef N (如果N宏定义了)
ifndef N (如果N宏没有定义)
static和extern
static修饰局部变量: 变量保存在常量区(静态变量), 第二次调用static int num = 123;的时候不会再次声明, 而是直接拿来用
static修饰的全局变量不能跨模块访问, extern修饰可以跨模块