文章目录
写在前面
1、基本规则
规则 | 说明 |
---|---|
程序的第一行: #include <stdio.h> | 告诉 C 编译器在实际编译之前要包含 stdio.h 文件 |
int main() 是主函数 | 程序从int main() 开始执行 |
空格、换行、注释程序不会读取 | 注释://、/* */、 |
每行以 ; 结束 | 分号是语句结束符 |
区分大小写 | C 是区分大小写的编程语言 |
变量、方法命名可以以“_”开始 | 一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9) |
实例
#include <stdio.h>
int main()
{
/* 我的第一个 C 程序 */
printf("Hello, World! \n");
return 0;
}
2、数据类型
类型 | 说明 |
---|---|
基本类型 | char、int、short、long、float、double、long double |
枚举类型 | enum |
void类型 | void |
派生类型 | 指针类型、数组类型、结构类型、共用体类型和函数类型 |
整数类型前面都可以加一个unsigned,表示该类型的值从0开始,char前面还可以加signed,表示值为-128 到 127。
例:unsigned char a = 1; signed char b = 2;
2.1、基本类型
基本类型就是字符型、整型、浮点这三大类
2.1.1、数值前缀
前缀用来表示数字进制
- 无前缀,默认十进制,10,31。
- 0 ,以0开头为8进制:045,021。
- 0b,以0b开头为2进制:0b11101101。
- 0x,以0x开头为16进制:0x21458adf。
2.1.2、数值后缀
后缀用来表示数值类型(大写与小写同义)
- 无后缀,整数默认int、浮点默认double
- 2.3 为双精度double(15 位有效位)
- 2.5f 为单精度float(6 位有效位)
- 11L 为long
- 11.1L为long double
- 10ul 为无符号long
2.1.3、字符和字符串
- 字符型,char 类型,用单引号,如char a = ‘m’;char b = 109; char c = ‘\n’;
- 字符串,通过字符指针或数组来间接实现,如char *a=“hello,world”、char b[]=“linux”、char site[7] = {‘R’, ‘U’, ‘N’, ‘O’, ‘O’, ‘B’, ‘\0’};
char *p=“hello,world” 这句代码的本质:指针 p 指向头"h"、尾"d" 的地址相连的一段内存
字符串操作:
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[14] = "runoob";
char str2[14] = "google";
char str3[14];
int len ;
/* 复制 str1 到 str3 */
strcpy(str3, str1);
printf("strcpy( str3, str1) : %s\n", str3 );
/* 连接 str1 和 str2 */
strcat( str1, str2);
printf("strcat( str1, str2): %s\n", str1 );
/* 连接后,str1 的总长度 */
len = strlen(str1);
printf("strlen(str1) : %d\n", len );
return 0;
}
2.2、枚举类型
枚举定义:
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY day;
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
enum
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
枚举的第一个给值默认为0,后面的值依次+1,
下面是枚举遍历实例:
#include <stdio.h>
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
int main()
{
// 遍历枚举元素
for (day = MON; day <= SUN; day++) {
printf("枚举元素:%d \n", day);
}
}
如果枚举的值不连续,则无法遍历,如下:
enum
{
ENUM_0,
ENUM_10 = 10,
ENUM_11
};
3、变量与函数
3.1、变量
变量定义
// 声明并定义变量, auto有和没有一样
int a;
char a = 'l';
auto int month;
// extern 声明变量
extern double b;
extern float b = 1.1f;
// const 常量,声明常量要在一个语句内完成
const long A = 1L;
// register 存储类用于定义存储在寄存器中,通常是一个字
register int a;
// static 修饰全局变量和局部变量的应用,它修饰的变量不会被重置
static int count=10;
// extern 是用来在另一个文件中声明一个全局变量或函数
extern int count;
3.2、函数
函数定义
int max(int num1, int num2)
{
int result = num1 + num2;
return result;
}
函数调用
t1.c
/* 函数定义 */
void swap(int *x, int *y)
{
int temp;
temp = *x; /* 保存地址 x 的值 */
*x = *y; /* 把 y 赋值给 x */
*y = temp; /* 把 temp 赋值给 y */
return;
}
t2.c
#include <stdio.h>
/* 函数声明 */
void swap(int *x, int *y);
int main ()
{
/* 局部变量定义 */
int a = 100;
int b = 200;
printf("交换前,a 的值: %d\n", a );
printf("交换前,b 的值: %d\n", b );
/* 调用函数来交换值
* &a 表示指向 a 的指针,即变量 a 的地址
* &b 表示指向 b 的指针,即变量 b 的地址
*/
swap(&a, &b);
printf("交换后,a 的值: %d\n", a );
printf("交换后,b 的值: %d\n", b );
return 0;
}
3.4、指针
3.4.1、变量指针
每一个变量都有一个内存位置,每一个内存位置都定义了可使用 & 运算符访问的地址
#include <stdio.h>
int main ()
{
int var_runoob = 10;
int *p; // 定义指针变量
p = &var_runoob;
printf("var_runoob 变量的地址: %p\n", p);
return 0;
}
指针*p前面的类型int,是指针所指向的数据的类型,指针自己的类型都是 “16进制地址值”。
指针等于NULL时,指向的地址是0x0,也就是空指针。
指针是可以运算的,如下:
#include <stdio.h>
const int MAX = 3;
int main ()
{
int var[] = {10, 100, 200};
int i, *ptr;
/* 指针中的数组地址 */
ptr = var;
for ( i = 0; i < MAX; i++)
{
printf("存储地址:var[%d] = %p\n", i, ptr );
printf("存储值:var[%d] = %d\n", i, *ptr );
/* 指向下一个位置 */
ptr++;
}
return 0;
}
执行结果
存储地址:var[0] = e4a298cc
存储值:var[0] = 10
存储地址:var[1] = e4a298d0
存储值:var[1] = 100
存储地址:var[2] = e4a298d4
存储值:var[2] = 200
3.4.2、函数指针
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数、传递参数。
#include <stdio.h>
int max(int x, int y)
{
return x > y ? x : y;
}
int main(void)
{
/* p 是函数指针 */
int (* p)(int, int) = & max; // &可以省略
int a, b, c, d;
printf("请输入三个数字:");
scanf("%d %d %d", & a, & b, & c);
/* 与直接调用函数等价,d = max(max(a, b), c) */
d = p(p(a, b), c);
printf("最大的数字是: %d\n", d);
return 0;
}
回调函数:函数指针作为某个函数的参数,如下例
#include <stdlib.h>
#include <stdio.h>
// 回调函数
void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
for (size_t i=0; i<arraySize; i++)
array[i] = getNextValue();
}
// 获取随机值
int getNextRandomValue(void)
{
return rand();
}
int main(void)
{
int myarray[10];
/* getNextRandomValue 不能加括号,否则无法编译,因为加上括号之后相当于传入此参数时传入了 int , 而不是函数指针*/
populate_array(myarray, 10, getNextRandomValue);
for(int i = 0; i < 10; i++) {
printf("%d ", myarray[i]);
}
printf("\n");
return 0;
}
4、程序结构
4.1、if
if(a == 10)
{
/* 当布尔表达式 1 为真时执行 */
}
else if(a == 11)
{
/* 当布尔表达式 2 为真时执行 */
}
else
{
/* 当上面条件都不为真时执行 */
}
4.2、switch
/* 局部变量定义 */
char grade = 'B';
switch(grade)
{
case 'A' :
printf("很棒!\n" );
break;
case 'B' :
default :
printf("无效的成绩\n" );
}
4.3、三元表达式
a > 1 ? 0 : 10;
4.4、while
while( a < 20 )
{
a++;
}
4.5、for
for( int a = 10; a < 20; a++ )
{
printf("a 的值: %d\n", a);
}
4.6、do…while
do
{
printf("a 的值: %d\n", a);
a = a + 1;
}while( a < 20 );
4.5、跳出和跳转
break; // 终止循环或 switch 语句
continue; // 跳出本次循环
goto; // 跳到某行
LOOP:do
{
if( a == 15)
{
/* 跳过迭代 */
a = a + 1;
goto LOOP;
}
printf("a 的值: %d\n", a);
a++;
}while( a < 20 );
5、结构体 struct
5.1、结构体定义
定义结构
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;
struct
{
int a;
char b;
double c;
} s1;
// 定义
struct SIMPLE
{
int a;
char b;
double c;
};
// 声明变量
struct SIMPLE t1, t2[20], *t3;
//也可以用typedef创建新类型
typedef struct
{
int a;
char b;
double c;
} Simple2;
//现在可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;
结构体里面可以有其他结构体
//此结构体的声明包含了其他的结构体
struct COMPLEX
{
char string[100];
struct SIMPLE a;
};
//此结构体的声明包含了指向自己类型的指针
struct NODE
{
char string[100];
struct NODE *next_node;
};
如果两个结构体互相包含,则需要对其中一个结构体进行不完整声明
struct B; //对结构体B进行不完整声明
//结构体A中包含指向结构体B的指针
struct A
{
struct B *partner;
//other members;
};
//结构体B中包含指向结构体A的指针,在A声明完后,B也随之进行声明
struct B
{
struct A *partner;
//other members;
};
5.2、结构体调用
结构体变量的初始化、调用实例:
#include <stdio.h>
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book = {"C 语言", "RUNOOB", "编程语言", 123456};
int main()
{
printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book.title, book.author, book.subject, book.book_id);
}
#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( )
{
struct Books Book1; /* 声明 Book1,类型为 Books */
struct Books Book2; /* 声明 Book2,类型为 Books */
/* Book1 详述 */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* Book2 详述 */
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/* 输出 Book1 信息 */
printf( "Book 1 title : %s\n", Book1.title);
printf( "Book 1 author : %s\n", Book1.author);
printf( "Book 1 subject : %s\n", Book1.subject);
printf( "Book 1 book_id : %d\n", Book1.book_id);
/* 输出 Book2 信息 */
printf( "Book 2 title : %s\n", Book2.title);
printf( "Book 2 author : %s\n", Book2.author);
printf( "Book 2 subject : %s\n", Book2.subject);
printf( "Book 2 book_id : %d\n", Book2.book_id);
return 0;
}
结构体也可以作为函数参数
#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
/* 函数声明 */
void printBook( struct Books book );
int main( )
{
struct Books Book1; /* 声明 Book1,类型为 Books */
struct Books Book2; /* 声明 Book2,类型为 Books */
/* Book1 详述 */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* Book2 详述 */
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/* 输出 Book1 信息 */
printBook( Book1 );
/* 输出 Book2 信息 */
printBook( Book2 );
return 0;
}
void printBook( struct Books book )
{
printf( "Book title : %s\n", book.title);
printf( "Book author : %s\n", book.author);
printf( "Book subject : %s\n", book.subject);
printf( "Book book_id : %d\n", book.book_id);
}
5.3、结构体指针
定义
struct Books *struct_pointer = &Book1;
使用指向该结构的指针访问结构的成员,须使用 -> 运算符,如下
struct_pointer->title;
实例
#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
/* 函数声明 */
void printBook( struct Books *book );
int main( )
{
struct Books Book1; /* 声明 Book1,类型为 Books */
struct Books Book2; /* 声明 Book2,类型为 Books */
/* Book1 详述 */
strcpy( Book1.title, "C语言基础");
strcpy( Book1.author, "zhangsan");
strcpy( Book1.subject, "编程语言");
Book1.book_id = 6495407;
/* Book2 详述 */
strcpy( Book2.title, "C语言进阶");
strcpy( Book2.author, "lisi");
strcpy( Book2.subject, "编程语言");
Book2.book_id = 6495700;
/* 通过传 Book1 的地址来输出 Book1 信息 */
printBook( &Book1 );
/* 通过传 Book2 的地址来输出 Book2 信息 */
printBook( &Book2 );
return 0;
}
void printBook( struct Books *book )
{
printf( "书籍标题: %s\n", book->title);
printf( "书籍作者: %s\n", book->author);
printf( "书籍分类: %s\n", book->subject);
printf( "书籍ID: %d\n", book->book_id);
}
6、公用体 union
一个公用体,可以赋值多种类型,但有其中一个类型正在使用,如下
#include <stdio.h>
#include <string.h>
union Data
{
int i;
float f;
char str[20];
};
int main( )
{
union Data data;
// 只有i在使用
data.i = 10;
printf( "data.i : %d\n", data.i);
// 只有f在使用
data.f = 220.5;
printf( "data.f : %f\n", data.f);
// 只有str在使用
strcpy( data.str, "C Programming");
printf( "data.str : %s\n", data.str);
return 0;
}
7、位域
位域在结构体中使用,用来限制一个数值的长度(转为二进制后的长度),如下例:
struct k{
int a:1;
int :2; /* 位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的。 */
int b:3;
int c:2;
};
int a:1;
表示该位域只能为0、1 (二进制)
int c:2;
表示该位域只能为00、01、10、11 (二进制)
位域类型只能是:int(整型),unsigned int(无符号整型),signed int(有符号整型) 三种类型。
使用实例:
int main(){
struct bs{
unsigned a:1;
unsigned b:3;
unsigned c:4;
} bit,*pbit;
bit.a=1; /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */
bit.b=7; /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */
bit.c=15; /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */
printf("%d,%d,%d\n",bit.a,bit.b,bit.c); /* 以整型量格式输出三个域的内容 */
pbit=&bit; /* 把位域变量 bit 的地址送给指针变量 pbit */
pbit->a=0; /* 用指针方式给位域 a 重新赋值,赋为 0 */
pbit->b&=3; /* 使用了复合的位运算符 "&=",相当于:pbit->b=pbit->b&3,位域 b 中原有值为 7,与 3 作按位与运算的结果为 3(111&011=011,十进制值为 3) */
pbit->c|=1; /* 使用了复合位运算符"|=",相当于:pbit->c=pbit->c|1,其结果为 15 */
printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); /* 用指针方式输出了这三个域的值 */
}
8、typedef 与 #define
- typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。
- typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。
typedef 实例
#include <stdio.h>
#include <string.h>
typedef struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} Book;
int main( )
{
Book book;
strcpy( book.title, "C 教程");
strcpy( book.author, "BeanInJ");
strcpy( book.subject, "编程语言");
book.book_id = 12345;
printf( "书标题 : %s\n", book.title);
printf( "书作者 : %s\n", book.author);
printf( "书类目 : %s\n", book.subject);
printf( "书 ID : %d\n", book.book_id);
return 0;
}
#define实例
#include <stdio.h>
#define TRUE 1
#define FALSE 0
int main( )
{
printf( "TRUE 的值: %d\n", TRUE);
printf( "FALSE 的值: %d\n", FALSE);
return 0;
}