c程序都是由若干个头文件和函数组成
#include
int main()
{
printf("Hello World!");
return 0;
}
char
char grade = ‘A’;
char grade = 65; //可以,但这并不是一个好的编程习惯
int
int a = 0;
int b = 22;
float和double
float a = 6.3e-33;
double b = 18;
double c = 100.;
数据类型的大小
#include
int main()
{ //单位:字节
printf("%d\n", sizeof(char)); //1
printf("%d\n", sizeof(short)); //2
printf("%d\n", sizeof(int)); //4
printf("%d\n", sizeof(long)); //4
printf("%d\n", sizeof(long long));//8
printf("%d\n", sizeof(float)); //4
printf("%d\n", sizeof(double)); //8
printf("%d\n", sizeof(long double));//8
return 0;
}
变量
#include
int c = 0;//全局变量若不初始化默认为0
int Add(int a, int b)//形参变量
{
return a + b;
}
int main()
{
int a = 18;//局部变量
int b = 23;
{
int a = 22;//局部变量
printf("a=%d ", a);
}
c = Add(a, b);//实参变量
printf("c=%d ", c);
printf("a=%d ", a);
return 0;
}
输出结果:a=22 c=41 a=18
常量
const int a = 10;
int arr[a] = {0};//程序报错,说明a是个变量
枚举常量
enum typeName{ name1 , name2 , name3 ,…};
#include
#define MAX 10
enum Sex
{
male,//若改为male=1,则female=2,这是赋初值
female,
};
int main()
{
enum Sex s = male;
//male=10;会报错
printf("%d ", MAX);//10
printf("%d ", male);//0
printf("%d ", female);//1
return 0;
}
转义字符 | 含义 | ASCII值 |
---|---|---|
\a | 警报 | 007 |
\b | 退格 | 008 |
\f | 换页 | 012 |
\n | 换行 | 010 |
\r | 回车 | 013 |
\t | 水平制表符 | 009 |
\v | 垂直制表符 | 011 |
\\ | 反斜杠 | 092 |
\’ | 单引号 | 039 |
\" | 双引号 | 034 |
\? | 问号 | 063 |
\ddd | ddd表示1~3个八进制数字 | |
\xdd | dd表示2个16进制数字 |
if语句
if ( expression )
statement;
如果对expression求值为真(非0),则执行statement,statement可以是简单语句也可以是复合语句
if else语句
if ( expression )
statement1;
else
statement2;
if else嵌套语句
if ( expression )
statement1;
else if
statement2;
else
statement3;
switch(整型表达式)
{
case 整型常量:语句;
}
#include
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
printf("星期一");
break;
case 2:
printf("星期二");
break;
case 3:
printf("星期三");
break;
case 4:
printf("星期四");
break;
case 5:
printf("星期五");
break;
case 6:
printf("星期六");
break;
case 7:
printf("星期七");
break;
default:
printf("输入错误");
}
return 0;
}
while循环
while ( expression)
{
statement;
}
#include //打印1-10
int main()
{
int i = 0;
while (i < 10)
{
i++;
printf("%d ", i);
}
return 0;
}
#include
int main()
{
int i = 0;
while (i < 10)
{
i++;
if (5 == i)
continue;
else if (9 == i)
break;
printf("%d ", i);//1 2 3 4 6 7 8
}
return 0;
}
for循环
for( 表达式1; 表达式2; 表达式3)
{
statement;
}
#include
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (i == 5)
continue;
if (i == 9)
break;
printf("%d ", i);//1 2 3 4 6 7 8
}
return 0;
}
do-while循环
do
{
语句;
}while(表达式);
#include
int main()
{
int i = 0;
do
{
i++;
if (i == 5)
continue;
if (i == 9)
break;
printf("%d ", i);//1 2 3 4 6 7 8
} while (i <= 10);
return 0;
}
库函数
自定义函数
void swap(int* x,int* y)//交换x和y的值,形式参数
{ //若在主函数后需声明void swap(int* x,int* y);
int temp = 0;
temp = *x;
*x = *y;
*y = temp;
}
int main()
{
int x = 1;
int y = 2;
printf("x=%d,y=%d\n", x, y);//1 2
swap(&x, &y);//实际参数
printf("x=%d,y=%d", x, y);//2 1
return 0;
}
#include
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}//答案:4321 ,printf()的会返回字符的个数,先打印43后返回2,在打印2返回1,再打印1
函数递归
#include
void Print(int n)
{
if (n > 9)
{
Print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
int num = 123;
Print(num);//打印1 2 3
return 0;
}
一维数组
数组的初始化:
int arr1[10] = { 1,2,3 };
int arr2[] = { 1,2,3,4 };
int arr3[5] = { 1,2,3,4,5 };
char arr4[3] = { ‘a’,98, ‘c’ };
char arr5[] = { ‘a’,‘b’,‘c’ };
char arr6[] = “abcdef”;
char arr7[] = “abc”;
char arr8[3] = { ‘a’,‘b’,‘c’ };
arr[]=“abcdef”
siezeof:计算arr所占空间的大小7
strlen:求字符串长度’\0’之前的字符个数,直到找到’\0’为止6
strlen:求字符串的长度,只能求对字符串求长度,需要引用库函数,头文件
sizeof是计算变量、数组、类型的大小,单位是字节,是个操作符
sizeof和strlen之间两者没有联系
sizeof(数组名)计算的是整个数组的大小,单位是字节
&数组名,数组名代表整个数组,取出的是整个数组的地址
#include
int main()
{
char arr[] = "abc";
char arr1[] = { 'a','b','c' };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr1));//答案是4 3 3 随机值(未找到\0结束标志)
return 0;
}
#include
int main()
{
int arr1[3][3];
int i = 0;
for (i = 0; i < 2; i++)
{
int j = 0;
for (j = 0; j < 3; j++)
{
printf("&arr1[%d][%d] = %p\n", i, j, &arr1[i][j]);
}
}
return 0;
}
算术操作符
#include
int main()
{
int a = 7/4;
float b = 7%4;
float c = 7 / 4.0;
printf("%d ", a);//1
printf("%lf ", b);//3.000000
printf("%lf", c);//1.750000
return 0;
}
移位操作符
移位操作符的操作数必须是整数
#include
int main()
{
int a = 2;//00000000 00000000 00000000 00000010
int b = a << 1;//0000000 00000000 00000000 000000100=4
printf("%d\n", b);//4
printf("%d"\n, a);//2
return 0;
}
int main()
{
int a = -1;//11111111 11111111 11111111 11111111
int b = a >> 1;//01111111 11111111 11111111 11111111或11111111 11111111 11111111 11111111
printf("%d\n", b);//当前平台是算术移位结果是-1
return 0;
}
位操作符
#include
int main()
{
int a = 1 & 2;//0001&0010 = 0000=0
int b = 1 | 2;//0001|0010 = 0011=3
int c = 1 ^ 2;//0001^0010 = 0011=3
printf("%d\n", a);
printf("%d\n", b);
printf("%d\n", c);
return 0;
}
赋值操作符
int a = 10;
int b = 20;
int a = 10;
a = a+10;
a+=10;//与上条代码是一样的效果,但是更加简洁
单目操作符
! | - | + | & | ~ | - - | ++ | * |
---|---|---|---|---|---|---|---|
逻辑取反 | 负值 | 正值 | 取地址 | 对二进制按位取反 | 自减 | 自增 | 解引用操作符 |
#include
int main()
{
int a = 1;
int a1 = 2;
int b = ++a;
int c = a1++;
printf("%d\n", a);//2
printf("%d\n", b);//2
printf("%d\n", c);//2
return 0;
}
关系操作符
> | >= | < | <= | != | == |
---|---|---|---|---|---|
大于 | 大于等于 | 小于 | 小于等于 | 不等于 | 等于 |
逻辑操作符 |
1&2的结果是0
1&&2的结果是1
1|2的结果是3
1||2的结果是1
条件操作符
int main()
{
int a = 1;
int b = 2;
int c = a > b ? a : b;
printf("%d", c);//2
return 0;
}
逗号表达式
include <stdio.h>
int main()
{
int a = 1;
int b = 2;
int c = (a > b, a < 10, a, b = a + 1);
printf("%d", c);//2
return 0;
}
结构成员
#include
struct book
{//结构体的成员变量
char name[10];
int price;
};
int main()
{
// int bk = 0;
struct book bk = { "c语言",50 };
printf("%s\n", bk.name);//结构体变量名.成员名
printf("%d\n", bk.price);
return 0;
}
#include
struct book
{//结构体的成员变量
char name[10];
int price;
};
int main()
{
// int bk = 0;
struct book bk = { "c语言",50 };
struct book* pbk = &bk;//指向结构体的指针
printf("%s\n", (*pbk).name);//结构体变量名.成员名
printf("%d\n", (*pbk).price);
return 0;
}
#include
struct book
{//结构体的成员变量
char name[10];
int price;
};
int main()
{
// int bk = 0;
struct book bk = { "c语言",50 };
struct book* pbk = &bk;//指向结构体的指针
printf("%s\n", pbk->name);//pbk是个结构体指针
printf("%d\n", pbk->price);//结构体指针->成员名
return 0;
}
char a,b,c;
a=b+c;
b和c的值被提升为普通整型,再执行加法运算,结果将被截断,再存储在a中
#include
int main()
{
char a = 1;
//00000000 00000000 00000000 00000001补码
//将1交给a时,因为a的类型为char类型即只有一个字节,
// 所以a中只能储存一个字节即8个比特位,进行截断只保留最后的8个比特位
//000000001 -a截断后
char b = 127;
//00000000 00000000 00000000 01111111补码
//01111111 -b截断后
char c = a + b;
//00000000 00000000 00000000 00000001
//00000000 00000000 00000000 01111111
//00000000 00000000 00000000 10000000
//10000000 截断后再进行整型提升
//11111111 11111111 11111111 10000000补码
//11111111 11111111 11111111 01111111反码
//10000000 00000000 00000000 10000000原码
printf("%d", c);//-128
return 0;
}
#include
int main()
{
char c = 1;
printf("%u\n", sizeof(c));//1
printf("%u\n", sizeof(+c));//4
printf("%u\n", sizeof(-c));//4
//c只要参与表达式运算, 就会发生整形提升
return 0;
}
运算符 | 描述 | 使用方法 | 结合方向 | 补充 |
---|---|---|---|---|
() | 圆括号 | (表达式)/函数名(形参名) | L->R | |
[ ] | 下标引用 | 数组名[常量表达式] | ||
. | 访问结构成员 | 结构体.成员名 | ||
-> | 访问指针结构成员 | 结构体指针->成员名 | ||
++ | 后缀自增 | a++ | ||
-- | 后缀自减 | a-- | ||
! | 逻辑反 | !a | R->L | |
~ | 按位取反 | ~a | ||
+ | 表示正值,单目 | +a,+可省略 | ||
- | 表示负值,单目 | -a | ||
++ | 前缀自增 | ++a | ||
-- | 前缀自减 | --a | ||
* | 间接访问,解引用 | *a | ||
& | 取地址 | &a | ||
sizeof | 计算长度,单位字节 | sizeof(a) | ||
(类型) | 类型转换 | (类型)a | ||
* | 乘法 | a*a | L->R | |
/ | 除法 | a/a | ||
% | 取余 | a%a | ||
+ | 加法 | a+a | ||
- | 减法 | a-a | ||
<< | 左移 | a<<1 | ||
>> | 右移 | a>>1 | ||
> | 大于 | a>a | ||
>= | 大于等于 | a>=a | ||
< | 小于 | a < a | ||
<= | 小于等于 | a<=a | ||
== | 等于 | a==a | ||
!= | 不等于 | a!=a | ||
& | 按位与 | a&a | ||
^ | 按位异或 | a^a | ||
| | 按位或 | a|a | ||
&& | 逻辑与 | a&&a | ||
|| | 逻辑或 | a||a | ||
? : | 条件操作符,三目 | exp?exp:exp | ||
= | 赋值 | a=b | R->L | |
+= | 以....加 | a+=b | ||
-= | 以....减 | a-=b | ||
*= | 以....乘 | a*=b | ||
/= | 以....除 | a/=b | ||
%= | 以....取模 | a%=b | ||
<<= | 以....左移 | a<<=b | ||
>>= | 以....右移 | a>>=b | ||
&= | 以....与 | a&=b | ||
^= | 以....异或 | a^=b | ||
|= | 以....或 | a|=b | ||
, | 逗号 | a,b |
#include
int main()
{
int a = 1; //a是变量,a的类型是int(整型)
int* p = &a; //p是指针变量,p的类型是int*,p里面存放的是a的地址
printf("%p", &a);//a是4个字节,取到的是a的4个字节中的第一个字节的地址
return 0;
}
#include
int main()
{
int a = 0x11223344;
char* pc = &a;
*pc = 0;
printf("%p\n", pc);
return 0;
}
野指针是指针指向的位置是不可知的,造成的原因有多种,如指针未初始化、指针越界访问等
如何规避?
指针和数组
int a = 1;
int* pa = &a;
int** ppa = &pa;
a的地址存放在pa中,pa的地址放在ppa中
pa是一级指针,ppa是二级指针
字符指针
#include
int main()
{
char a = 'a';
char* pc = &a;
*pc = 'b';
printf("%c %c", a, *pc);//b b
return 0;
}
p储存的只是字符串首元素的地址,%s需要的是指针变量,会一直向后打印直到遇到\0,由于存的是首元素的地址,故解引用时,只会打印a
#include
int main()
{
char* p = "abcd";//字符串常量,不能被修改,最好加const进行修饰
printf("%c ", *p);//a
printf("%s ", p);//abcd
return 0;
}
指针数组
int main()
{
int arr[5] = { 0 };//整型数组
char ch[5] = { 0 };//字符数组
int* parr[3];//存放整型指针的数组-指针数组
char* pch[2];//存放字符指针的数组=字符数组
//[]的优先级高于*
return 0;
}
#include
int main()
{
int a = 1;
int b = 2;
int c = 3;
int* arr[3] = { &a,&b,&c };
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%d ", *(arr[i]));//1 2 3
}
return 0;
}
#include
int main()
{
int arr1[3] = { 1,2,3 };
int arr2[3] = { 4,5,6 };
int arr3[3] = { 7,8,9 };
int* arr[] = { arr1,arr2,arr3 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 3; j++)
{
printf("%d ", *(arr[i] + j));//arr[i]是某个数组首元素的地址,+j是该数组的其后元素的地址,最后解引用求出该值,
} //也可以写成arr[i][j]
printf("\n");
}
return 0;
}
数组指针
数组指针是指向数组的指针,是用来存放数组的地址
int main()
{
int* p = NULL;//p是整型指针-指向整型的指针-可以存放整型的地址
char* pc = NULL;//pc是字符指针-指向字符的指针-可以存放字符的地址
int arr[10] = { 0 };
//arr-首元素的地址
//&arr[0]-首元素的地址
//&arr-数组的地址
//整型指针是用来存放整型的地址
//字符指针是用来存放字符的地址
//数组指针是用来存放数组的地址
int arr1[3]={1,2,3};//这个数组3个元素,每个元素是个整型
int (*parr1)[3]=&arr1;//数组的地址要存起来,要用数组指针
//parr1就是数组指针,指向了一个数组,这个数组3个元素,每个元素是个整型
return 0;
}
int main()
{
char* arr[6];
char* (*pa)[6] = &arr;//pa是数组的地址,用数组指针存储
//指针pa指向的是数组arr,
//pa指向的数组arr是6个元素,每个元素是类型char*
return 0;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//这种用法比数组指针方法简单
int* p = arr;
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
//一般不这么用数组指针,比较麻烦,指针数组一般用于二维数组
//int(*pa)[10] = &arr;
//int i = 0;
//for (i = 0; i < 10; i++)
//{
// printf("%d ",(*pa)[i]);//对数组的地址进行解引用得到的是整个数组
int* p=&a;,p存储的是a的地址,对p进行解引用*p,得到是a,类比
pa存储的是数组arr的地址,对pa进行解引用*pa,得到的是arr
// //printf("%d", *(*pa + i));// *p==arr即*(arr+i)
//}
return 0;
}
#include
void print(int(*p)[3], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < y; j++)
{
printf("%d ", *(*(p + i) + j));//*(p+i)是某一行的地址
} //p[i][j]
}
} //p+i是第i行的地址,*(p+i)就是对这一行的地址解引用==p[i]==这一行的数组名,即首元素的地址
int main()
{
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
print(arr, 3, 3);
return 0;
}
函数指针
#include
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 1;
int b = 2;
printf("%p\n", Add);
printf("%p\n", &Add);
return 0;
}
int(*pa)(int, int),去掉pa就是指针的类型,去掉(*pa)就是指针指向元素的类型
#include
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 1;
int b = 2;
int(*pa)(int, int) = Add;//pa存的是函数的地址,*pa找到这个函数
printf("%d ", (*pa)(1, 2));//3....*可有可无, &函数名和函数名都是函数的地址,调用可以直接Add(1,2)==pa(1,2)
printf("%d ", pa(1,2));//3
return 0;
}
//signal是一个函数声明
//signal函数的参数有2个,第一个是int,第二个是函数指针,该函数指针指向的函数的参数是int,返回类型是void
//signal函数的返回类型也是一个函数指针,该函数指针指向的函数的参数是int,返回类型是void
void (*signal(int, void(*)(int)))(int);
//该函数signal的返回类型是void (*)(int)-太复杂
typedef void(*p_sig)(int);//将void (*)(int)重新定义为p_sig
p_sig signal(int, p_sig);
//这两句等同于第一句
函数指针数组
#include
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
int main()
{
int(*parr[4])(int, int) = { Add,Sub,Mul,Div };
int i = 0;
for (i = 0; i < 4; i++)
{
printf("%d\n", parr[i](1, 2));//3 -1 2 0
}
return 0;
}
指向函数指针数组的指针
int arr[10] = { 0 };
int(*p)[10] = &arr;//取出数组的地址,存到数组指针
int(*pf)(int, int);//函数指针
int (pfarr[4])(int, int);//pfarr是个数组,是函数指针的数组
int ((ppfarr)[4])(int, int)=&pfarr;
//ppfarr是一个数组指针,指针指向的数组有4个元素
//指向的数组的每个元素的类型是一个函数指针,类型是int()(int ,int)
回调函数
struct book
{
char name[20];
int price;
};
int main()
{
struct book bk = { “c语言”,20 };
return 0;
}
或者
typedef struct book
{
char name[20];
int price;
}bk1;
int main()
{
bk1 b1 = { “c语言”,20 };
return 0;
}
结构体成员的访问
#include
typedef struct book
{
char name[20];
int price;
int x;
double y;
}bk1;
struct s
{
int a;
bk1 b;
char *pc;
};
int main()
{
char arr[] = "hello";
struct s s1 = { 1,{"张三",20,2,1.0},arr };
printf("%d\n", s1.a);
printf("%s\n", s1.b.name);
printf("%s\n", s1.pc);
return 0;
}
结构体传参
#include
typedef struct book
{
char name[20];
int price;
double y;
}bk1;
void Print(bk1* tmp)
{
printf("%s\n", tmp->name);
printf("%d\n", tmp->price);
printf("%f\n", tmp->y);
}
int main()
{
bk1 b = { "张三",1,2.0 };
// Print(b);
Print(&b);//这种方式好函数传参的时候,参数是需要压栈的。
//如果传递一个结构体对象的时候,结构体过大,
//参数压栈的的系统开销比较大,所以会导致性能的下降。
return 0;
文章难免有些错误,请大家指正!共同进步!!!