数据类型
基本类型
整型 signed short
int long
unsigned long long
字符型 char
实型 float double
枚举型 enum
构造类型
数组
结构性 struct
共用体 union
指针类型
空类型
void
逻辑类型
bool 非零(true),零(false)
运算
运算符
算数运算符
逻辑运算符
&& 与
|| 或
! 非
位运算符
& 与(位)
| 或(位)
^ 异或(位)
~ 非(位)
关系运算符
> >= < <= == !=
=赋值 ==等于
赋值运算符
= += -= *= %=
a-=5;=====a=a-5;
a++;//a=a+1;
a+=3;//a=a+3;
条件运算符(三目运算符)
格式: 表达式?表达式2:表达式3;
成立运行表达式2,不成立运行表达式3
int a=3,b=6;
c=a>b?a:b; //求最大值
关键字:
存储类型(决定变量存放的位置):auto(自动型) static(静态) extern(外部引 用) register(寄存器) (c用不到,我们放到最后讲)
数据类型(决定变量所占的空间大小):int(整型4) char(字符型1) short(短整型2) long(长整型4) float(单精度浮点型4) double(双精度浮点型8) signed(有符号) unsigned(无符号)
int a;//(signed)int a;
构造数据类型(用户可自定义类型):struct(结构体) union(共用体) enum(枚举)
选择结构:if else switch case default
循环结构:for while goto do break continue
其他:void(空类型 在函数、指针会见到) typedef(重定义 在结构体会见到,结构体名字比较长,可以起个小名) const(常量化 readonly 和void一起在指针会讲) sizeof(计算数据所占空间大小) volatile(防止编译器优化 ,平常用不到) return(返回值)
逻辑运算
整数的二进制表示有3种:原码、反码、补码
整数在内存中存储是补码的二进制数
| 原码 | 反码 | 补码 | |
|
正数 | 本身 | 本身 | 本身 |
| 负数 | 本身 | 符号位外按位取反 | 反码加一 |
int 占4字节 1字节=8位 32位 0正数 1负数
-6原码:
1000 0000 0000 0000 0000 0000 0000 0110
-6反码:
1111 1111 1111 1111 1111 1111 1111 1001
-6补码:
1111 1111 1111 1111 1111 1111 1111 1010
截断法则:
逻辑与运算:当前边的表达式结果为假,后边表达式不再执行,直接返回假。
逻辑或运算:当前边的表达式结果为真,后边表达式不再执行,直接返回真。
变量
格式:存储类型 数据类型 变量名
auto int a;
存储类型:决定变量存储位置
数据类型:决定开辟的空间大小
变量名:遵循标识符的命名规则
| 名称 | 字节大小 | 取值范围 | |
| int | 整型 | 4 | |
| char | 字符型 | 1 | -2^7~2^7-1 |
| short | 短整型 | 2 | |
| long | 长整型 | 4 | |
| float | 单精度浮点型 | 4 | 有效位数6-7位 |
| double | 双精度浮点型 | 8 | 有效位数15-16位 |
| 局部变量 | 全局变量 | |
| 定义位置 | 函数体内部 | 函数体外部 |
| 初值 | 未初始化时值为随机值 | 未初始化时值为0 |
| 存储位置 | 栈区 | 全局区 |
| 生命周期 | 同函数体共存亡 | 同程序共存亡 |
| 作用域 | 当前函数体内部 | 整个程序 |
常量
字符常量
用单引号(' ')包裹
char a='w'
'w'---> 字符
a --->变量
字符串常量
用双引号(" ")包裹
char a[ ] ="hello"
整型常量
八进制 十进制 十六进制
浮点型常量
float 4 字节
标识常量
格式:#define 宏名 常量或表达式或代码段
特点:只是单纯的替换,不进行计算
宏定义:起标识作用,宏名遵循标识符命名规则,一般用大写表示
#include<stdio.h>
#define N 5
#define M N+2
#define NUM 2+M*2+1 //2+5+2*2+1
int main(int argc, char const *argv[])
{
printf("%d\n",NUM); //12
return 0;
}
输入输出
按字符输入输出
输入:
int res=getchar();printf("%d\n",res);
输出:
int putchar(int c);
功能:向终端输出
参数:输出字符的ASCII值
返回值:输出字符的ASCII值
int res=getchar();putchar(res);
按格式输入输出
int printf(const char *format, ...);
功能:按格式向终端输出
参数:多参
返回值:输出数据个数
格式:
%d int
%c char
%f float
%lf double
%s 字符串
%p 地址
%o 八进制
%#x 十六进制
浮点型 默认打印小数点后六位
float a=2.3;
printf("hello %.2f\n",a); //保留2位小数
输入
int scanf(const char *format, ...);
功能:按格式向终端输入
参数:多个
返回值:正确输入数据的个数
int a;scanf("%d",&a);
printf("hello %d\n",a);
分支语句
if_else0
结构:
if(表达式1)
{
代码段1;
}else if(表达式2)
{
代码段2;
}else
{
代码段3;
}
switch_case
switch (表达式){
case 常量1:
/* code1 */
break;
case 常量2:
/* code2 */
break;
default:
/* code3 */
break;
}
循环
for while
for
格式
for (变量初值;终止条件;变量增减)
{
代码段;
}
int i,j;
for(i=1;i<10;i++)
{
for(j=1;j<=i;j++)
{
printf("%d*%d=%2d ",i,j,i*j); // %2d 位宽
}
printf("\n");
}
位宽表示
%3d 给输出三个位宽(字符数小于位宽默认右对齐)
while
while(表达式) //表达式为真则一直循环
{
}
do...while()
do
{
}while(表达式); //先执行再判断
循环控制语句
break:终止循环
continue:结束本次循环,进行下个循环
return:终止程序
数组
特点:
内存连续
数据类型相同
分类:
一维数组
格式:存储类型 数据类型 数组名[元素个数]
auto int/char a[5]
ex: int a[6]={2,3,1,5,1,5};
a[0],a[1],a[2].......a[5] //a[n]为索引(n<6)
数组名
同为数组首地址
字节大小
sizeof(a) //表示字节大小
初始化
完全初始化 //定义数组规定元素个数等于定义个数
部分初始化 //定义数组规定元素个数不等于定义个数
未初始化 //定义规定元素个数但未定义元素
内存分配
int a[5]={2,3,4,5,6};
for(int i=0;i<5;i++)
printf("%p\n",&a[i]); //a[i]的地址
清零函数
bzero
#include <strings.h>
void bzero (void*s,size_t n);
功能:清空数组
参数:数组首地址
返回值:
int a[5]={4,3,2,5,1};
bzero(a,sizeof(a)); //将数组所有元素清零
memset
#include <string.h>
void *memset(void *s, int c, size_t n);
功能:清空函数
参数:数组首地址,c 替换的数据,n:清空的字节大小
返回值:数组首地址
int a[5]={2,5,6,4,3};
memset(a,0,sizeof(a)); //c基本取0
for(int i=0;i<5;i++)
printf("%d\n",a[i]);
若c=1 int函数为4字节 赋值为 0000 0001 0000 0001 0000 0001 0000 0001 =16,843,009
字符数组
char a[7]={"dsads"};
char b[ ]="dsada";
char c[ ]="dsacc dsaf";
char a1[]={'a','b','c'}; //数据类型是字符型,sizeof(a1)==3
char a2[]={"abc"}; //数据类型是字符串,sizeof(a2)==4 '\0'
字符串输入输出
1. 用for 循环
char a[6]="cscacs";
for(int i=0;i<6;i++)
printf("%s",a);
2. gets( ) 输入/ puts( ) 输出
功能:向终端输出字符串
参数:字符串首地址
返回值:输出字符个数
char a[33];
int b=puts(a); //字符个数
gets(a); //输入数组
puts(a); //输出数组
printf("%d",b); //输出字符个数
scanf("%s",a); //不支持输入空格
scanf("%[^\n]",a); //支持输入空格
3. strcpy(s,"cscaca") //复制字符串到此地址
计算字符串实际元素个数
int i;
for(i=0;a[i]!='\0';i++); //连加到元素为 ’\0‘ ==字符个数
printf("%d\n",i);
string.h (主函数类型)
#include <string.h>
size_t strlen(const char *s);
功能:计算字符串实际元素个数
参数:字符串首地址
返回值:实际元素个数
sizeof 与 strlen 的区别:
1. sizeof 为关键字,strlen 为函数
2. sizeof 计算实际开辟的空间大小, strlen 计算字符串实际元素个数
3. strlen 只对字符串进行计算
排序
冒泡排序

#include <stdio.h>
int main(int argc, char const *argv[])
{
int a[5];
int i, j, f; //定义变量,数组
for (i = 0; i < 5; i++)
{
scanf("%d", &a[i]); //输入数组
}for (i = 0; i < 4 ; i++) //行循环
{for (j = 0; j < 4- i ; j++) //列循环
{
if (a[j] > a[j + 1]) //找最大值
{
f = a[j];
a[j] = a[j + 1]; //替换最大值到最后
a[j + 1] = f;
}
}
}
for (i = 0; i < 5; i++)
{
printf("%d", a[i]); //输出数组
}return 0;
}
选择排序

#include <stdio.h>
int main(int argc, char const *argv[])
{
int a[8];
int i, j, f;
int min = 0;
for (i = 0; i < 8; i++)
{
scanf("%d", &a[i]); //输入数组
}for (i = 0; i < 8; i++)
{
min = i;
for (j = i + 1; j < 8; j++)
{
if (a[min] > a[j])
{
min = j;
} //排序主体
}if (i != min)
{
f = a[i];
a[i] = a[min];
a[min] = f;
}
}for (i = 0; i < 8; i++)
{
printf("%d", a[i]); //输出主体
}return 0;
}
二维数组
格式: 存储类型 数据类型 数组名[行数][列数]
int a[4][2]
int a[4][2]={2,5,1,5,3,7,2,5};
printf("%d %d\n",a[0][0],a[2][1]);
元素:
| a[0][0] | a[0][1] |
| a[1][0] | a[1][1] |
int a[2][3]={{1,2,3},{4,5,6}}; //按行进行赋值
int a[][3]={1,2,3,4,5,6}; //可以省略行数
int a[2][]={1,2,3,4,5,6}; //错误
初始化:
全部初始化 //所有元素全部赋值
部分初始化 //部分元素赋值
未初始化 //全部未赋值
循环遍历
int a[2][3]={1,2,3,4,5,6};
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
printf("%d\n",a[i][j]);
}
}
内存分配
int a[2][3]={1,2,3,4,5,6};
| 地址 | 地址 | 地址 | 元素 | 位置 |
| a[0] | a | &a[0][0] | 1 | a[0][0] |
| a[0]+1 | &a[0][1] | 2 | a[0][1] | |
| a[0]+2 | 3 | |||
| a[1] | a+1 | 4 | ||
| a[1]+1 | 5 | |||
| 6 |
指针
一级指针
变量名:存储普通变量的地址
格式:存储类型 数据类型 *指针变量名
int *p
int a=5;
int *p=&a; //p表示a的地址
char b='q';
char *p1=&b;
访问:
int a=5;
int *p=&a;
printf("%d %d\n",a,*p); // 打印内容为5
printf("%p %p\n",p,&a); // 打印5的地址
指针操作符
*:取地址里边的内容&:取地址符:取变量的地址
*&a: ===a 错误
&*a: 错误 ===p
初始化
1) int a=5;
int *p=&a; //定义指针的同时,直接初始化
2)int *p=NULL; //先定义一个空指针,后边可以重新赋值
指针 p 指向变量 a,*p可以访问到 a 的值
可以通过*p 间接修改变量a 的值
int a=5;
int *p=&a;
*p=66;
printf("%d %d\n",*&a,*p); //输出66 66
printf("%p %p\n",p,&a); //相同地址
将指针变量里面保存的地址赋值给另一个指针变量
float a=1.3;
float *p = &a;
float *q = p; //float *q=&a;
指针运算
算术运算
p++ //指针向高地址方向移动一个数据单位(int 4字节;char 1字节),指针的指向发生改变
p+1 //指针访问高地址方向第n个元素,指针的指向不发生改变
验证:同一个数组,两个地址之间的差值=相差元素个数
int m = 100;
double n = 200;
int *p = NULL;
double *q = NULL;
p = &m;
q = &n;
printf("m=%d &m=%p\n", m, &m); //
printf("p=%p p+2=%p\n", p, p + 2);
printf("n=%lf &n=%p\n", n, &n);
printf("q=%p q+2=%p\n", q, q + 2);

关系运算
< > ==
高地址>低地址
字符串倒序输出
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char a[] = "I LOVE CHINA";
char m, n, l;
char *p = a;
char *b = p + strlen(a) - 1;
while (p < b)
{
m = *p;
*p = *b;
*b = m;
p++;
b--;
}
char *i = a;
char *j = i;
while (*j != ' ')
{
j++;
}
j--;
while (i < j)
{
n = *i;
*i = *j;
*j = n;
i++;
j--;
}
j += 4;
char *k = j;
while (*k != ' ')
{
k++;
}
k--;
while (j < k)
{
l = *j;
*j = *k;
*k = l;
j++;
k--;
}
printf("%s\n", a); //输出 “CHINA LOVE I”
return 0;
}
指针的大小
int a=3;
int *p1=&a;
printf("%d\n",sizeof(p1)); //4
char b='q';
char *p2=&b;
printf("%d\n",sizeof(p2)); //4
getconf LONG_BIT 查看操作系统位数
32位操作系统,指针大小为4字节 1字节==8位
8位16进制4*8=32位二进制=4字节
64位操作系统,指针大小为8字节
指针修饰
const
const常量化 read-only只读
修饰普通变量 不能直接通过变量名修改
const int a=5; //int const a=5;
a+=6; //error
通过指针修改
const int a=5;
int *p=&a;
*p=88;
printf("%d %d\n",a,*p);
修饰指针
int const *p; //const修饰*p 指针指向的内容不能修改;但是指针的指向可以修改
int a=5;
const int *p=&a;
1)*p=33; //error
2) int b=33;
p=&b; //正确
修饰p
int * const p=&a; //const修饰p 指针的指向不能改,指针指向的内容可以改
int a=5;
int * const p=&a;
p=&b; //错误
*p=33;
printf("%d %d\n",a,*p);
void
不能修饰普通变量,修饰指针表示任意类型的指针
void a; //错误
void *p; //任意类型的指针
一般在函数参数或函数返回值中用到
void *memset(void *s,int c,size_t n);
void *p; //任意类型的指针
强制转换成int 类型指针 (int*)p
取内容*(int*)p
void *p=NULL;int a=5;
p=&a;
printf("%p %p\n",(int *)p,&a); //强转只在当前一行有效
printf("%d %d\n",*(int *)p,a);
void *p=NULL;int a=5;
int *q=(int *)p;
q=&a;
printf("%p %p\n",q,&a);
printf("%d %d\n",*q,a);
大小端
大端:低地址里边存放高字节数据,高地址里边存放低字节数据
小端:低地址里边存放低字节数据,高地址里边存放高字节数据
ex:0x12345678
大端:0x12 0x34 0x56 0x78
小端:0x78 0x56 0x34 0x12
int a=0x12345678;
char b;
b=(char)a;
printf("%#x\n",b);//0x78
int x[5] = {10, 20, 30};
int *px = x;
printf("%d,", ++*px); //取x[0]内容然后加1 //11
printf("%d\n", *px); //上面执行后的*px的内容 //11
px = x;
printf("%d,", (*px)++); //先输出上方执行后的内容再加1 //11
printf("%d\n", *px); //输出上方加1后的内容 //12
px = x+1; //指针向后移动一位(相对于初始位置)
printf("%d,", *px++); //先输出x[1]内容再指针向后移动一位 //20
printf("%d\n", *px); //输出上方执行后的内容x[2] //30
px = x+1; //指针向后移动一位(相对于初始位置)
printf("%d,", *++px); //先向后移动一位再输出对应x[2]的内容 //30
printf("%d\n", *px); //输出上方执行后的内容 //30
二级指针
一级指针存放普通变量的地址
二级指针存放一级指针的地址
格式:存储类型 数据类型 **指针变量名
int **p;
int a=8;int *p=&a;
int **q=&p;
访问a的值: a *p **q
访问a的地址: &a p *q
访问p的地址: q &p
指针和数组
指针和一维数组
直接访问:通过数组名
间接访问:通过指针
int a[]={2,3,4,5,6};
int *p=a;
直接访问:
|
地址 |
数组 |
元素 | ||
|
a |
&a[0] |
2 |
a[0] |
*a |
|
a+1 |
&a[1] |
3 |
a[1] |
*(a+1) |
|
a+2 |
&a[2] |
4 |
a[2] |
*(a+2) |
|
a+3 |
&a[3] |
5 |
a[3] |
*(a+3) |
|
a+4 |
&a[4] |
6 |
a[4] |
*(a+4) |
间接访问
|
地址 |
数组 |
元素 | ||||||
|
&p[0] |
p |
a |
&a[0] |
2 |
a[0] |
*a |
*p |
p[0] |
|
&p[1] |
p+1 |
a+1 |
&a[1] |
3 |
a[1] |
*(a+1) |
*(p+1) |
p[1] |
|
&p[2] |
p+2 |
a+2 |
&a[2] |
4 |
a[2] |
*(a+2) |
*(p+2) |
p[2] |
|
&p[3] |
p+3 |
a+3 |
&a[3] |
5 |
a[3] |
*(a+3) |
*(p+3) |
p[3] |
|
&p[4] |
p+4 |
a+4 |
&a[4] |
6 |
a[4] |
*(a+4) |
*(p+4) |
p[4] |
a和p本质不同:a是地址常量,不能被赋值;p是指针变量,可以被重新赋值
运算方法:
1)*和 ++都是单目运算符,优先级相同
2)单目运算符从右向左运算
(*p)++:先算(*p)==取内容,对内容++
*p++:先算p++,由于++在后,对p取*,最后再p++
*(p++)::同上
++*p:先算*p得到内容,再去 ++内容
++(*p):同上
*++p:先算++p,由于++在前,p先自加,对自加后的地址取内容
*(++p):同上
char *p="hello";
//p在栈区开辟4字节的空间存放字符串常量"hello"的首地址
//"hello"存放在常量区
char a[]="world";
二维数组和指针
int a[2][3]={2,3,4,5};//a:第一行的首地址 a+1:第二行的首地址
a是行地址,如果想访问其中的列(行地址和列地址级别不同,一行可以有多列),需要对他降级处理加*
a: 第一行的首地址
a+1: 第二行的首地址
*a: 第一行第一列的地址
int a[2][3]={2,3,4,5,6,7};
printf("%p\n",a); //第一行的首地址
printf("%p\n",*a); //第一行第一列的地址
printf("%p\n",*a+1); //第一行第二列的地址
printf("%d\n",*(*a+1)); //取第一行第二列的内容
printf("%p\n",a+1); //第二行的首地址
printf("%p\n",*(a+1)); //第二行第一列的地址
printf("%p\n",*(a+1)+1); //第二行第二列的地址
printf("%d\n",*(*(a+1)+1)); //取第二行第二列的内容
|
地址 |
元素 | |||||
|
a[0] |
*a |
a |
2 |
a[0][0] |
**a |
*a[0] |
|
a[0]+1 |
*a+1 |
3 |
a[0][1] |
*(*a+1) |
*(a[0]+1) | |
|
a[0]+2 |
*a+2 |
4 |
a[0][2] |
*(*a+2) |
*(a[0]+2) | |
|
a[1] |
*(a+1) |
a+1 |
5 |
a[1][0] |
*(*(a+1)) |
*a[1] |
|
a[1]+1 |
*(a+1)+1 |
6 |
a[1][1] |
*(*(a+1)+1) |
*(a[1]+1) | |
|
a[1]+2 |
*(a+1)+2 |
7 |
a[1][2] |
*(*(a+1)+2) |
*(a[1]+2) |
访问a[i][j]的地址:
a[i]+j *(a+i)+j
访问a[i][j]的值:
*(a[i]+j) *(*(a+i)+j)
数组指针
本质是指针,指向数组
格式:存储类型 数据类型 (*指针变量名)[列数]
(*a)[3]
int a[2][3]={2,3,4,5,6,7};
int (*p)[3]=a; //3:要3个3个运算
printf("%p %p\n",a,p);
printf("%p %p\n",a+1,p+1);
p可以代替a进行元素访问,但是本质不同
|
地址 |
元素 | |||||||
|
p[0] |
*p |
a[0] |
*a |
a |
2 |
a[0][0] |
**a |
*a[0] |
|
p[0]+1 |
*p+1 |
a[0]+1 |
*a+1 |
3 |
a[0][1] |
*(*a+1) |
*(a[0]+1) | |
|
p[0]+2 |
*p+2 |
a[0]+2 |
*a+2 |
4 |
a[0][2] |
*(*a+2) |
*(a[0]+2) | |
|
p[1] |
*(p+1) |
a[1] |
*(a+1) |
a+1 |
5 |
a[1][0] |
*(*(a+1)) |
*a[1] |
|
p[1]+1 |
*(p+1)+1 |
a[1]+1 |
*(a+1)+1 |
6 |
a[1][1] |
*(*(a+1)+1) |
*(a[1]+1) | |
|
p[1]+2 |
*(p+1)+2 |
a[1]+2 |
*(a+1)+2 |
7 |
a[1][2] |
*(*(a+1)+2) |
*(a[1]+2) |
访问a[i][j]的地址:
p[i]+j *(p+i)+j
访问a[i][j]的值:
*(p[i]+j) *(*(p+i)+j)
数组指针的大小:
int a[2][3]={2,3,4,5,6,7};
int (*p)[3]=a;
printf("%d\n",sizeof(p)); //4
遍历二维数组:
int a[2][3]={2,3,4,5,6,7};
int (*p)[3]=a;
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
printf("%d\n",*(p[i]+j)); //*(*(p+i)+j)
}
}
指针数组
本质是数组,里边存放地址
格式:存储类型 数据类型 *数组名[元素个数]
应用:
存放普通变量的地址
int a=3,b=5,c=9;
int *p[3]={&a,&b,&c};
p[0]--->&a
p[1]--->&b
p[2]--->&c
访问b的值:
*p[1] //p[1]访问指针数组的第二个元素,但是第二个元素是个地址,*p[1]
*(*(p+1)) //p+1访问的数组第二个元素的地址 *(p+1)取第二个元素的内容==&b;*(*(p+1))
访问b的地址:
p[1]
*(p+1)
存放二维数组每一行第一列的地址
int a[3][4]={2,3,4,5,6,7,8,9};
int *p[3]={a[0],a[1],a[2]};
访问a[1][2]的值:
*(p[1]+2) p[1]访问数组中第二个元素(第二行第一列的地址),p[1]+2找到第二行第三列的地址,*(p[1]+2)
*(*(p+1)+2) //p+1找到数组中第二个元素的地址(a[1]的地址),*(p+1)==第二行第一列的地址,*(p+1)+2==第二行第三列的地址,*(*(p+1)+2)
访问a[1][2]的地址:
p[1]+2
*(p+1)+2
printf("%d\n",sizeof(p)); //12 3个指针
存放字符串
char *p[3]={"hello","world","hqyj"};
打印world
printf("%s\n",p[1]);
printf("%s\n",*(p+1));
打印'd'
*(p[1]+4)
*(*(p+1)+4) p+1找到数组中第二个元素的地址, *(p+1)取数组中第二个元素的内容(world的首地址),*(p+1)+4访问到 从w的位置移动4个字节到d的位置,*(*(p+1)+4)
p[1][4]
命令行参数
argv:就是一个指针数组,里面存放的是命令行传递的字符串
argc:表示argv指针数组里面存储数据的个数,即命令行传递字符串的个数
#include<stdio.h>
int main(int argc, char const *argv[])
{
printf("%s\n",argv[1]);
printf("%d\n",argc);
return 0;
}
int a=5;
int *p=&a;
int **q=&p;
q=&p;
*q=*&p=p=&a
**q=*p=*&a=a
直接:a[0] a[1] *a
间接:*p p[0]
++ *
二维数组地址:&a[0][0] *a+1 *(a+1)+2 a[0]+2
数组指针
int (*p)[3] *p+1 *(p+1)+2
int a=2,b=5,c=8;
int *p[3]={&a,&b,&c};
*p[1] **(p+1)
int a[2][3]={2,3,4,5,6,7};
int *p[3]={a[0],a[1],a[2]};
p[1]数字第二个元素(第二行第一列的地址) p[1]+1(第二行第二列的地址) *( p[1]+1)
p+1数组第二个元素的地址(a[1]的地址),*(p+1)==第二行第一列的地址, *(p+1)+1--->*(*(p+1)+1)
char *p[3]={"abc","def","ghi"};
函数
功能、参数、返回值
{
代码段;
return 变量名或常量或表达式
}
注意 return 的返回值类型要和定义函数时的数据类型保持一致
声明
数据类型 函数名()
定义的函数可以直接写在主函数上边,也可写在下边,注意:写在下边时,要提前声明
格式
不需要参数,也不需要返回值
函数调用:函数名();
#include<stdio.h>
void hq();
int main(int argc, char const *argv[])
{
hq();
printf("aaaa\n");
hq();
hq();
return 0;
}
void hq()
{
printf("hqyjyyds\n");
printf("123456\n");
}
需要参数,不需要返回值
函数调用:函数名(实参列表);
#include<stdio.h>
void hq(int a,int b)
{
int sum=a+b;
printf("%d\n",sum);
}
int main(int argc, char const *argv[])
{
hq(5,8);
return 0;
}
不需要参数,需要返回值
#include<stdio.h>int hq()
{
int sum=5+8;
printf("%d\n",sum);
return sum;
}
int main(int argc, char const *argv[])
{
int res=hq();
printf("%d\n",res);
return 0;
}
需要参数,需要返回值
#include<stdio.h>
int hq(int a,int b)
{
int sum=a+b;
printf("1:%d\n",sum);
return sum;
}
int main(int argc, char const *argv[])
{
int res=hq(5,6);
printf("**%d\n",res);
printf("+++%d\n",hq(8,9));
return 0;
}
形参:函数定义时,定义的形参变量,是形式上存在的参数,只有在调用函数时才开辟内存空间。
实参:调用函数时,实际传递的值。
练习:写一个函数,求字符串中某个字符出现的次数hello l

函数传参
值传递
单向传递,把实参传递给形参使用,改变形参实参不受影响
(把值复制一份,进行修改,不影响原来的内容)

地址传递
双向传递 修改形参,实参会一起改变
(把变量的地址传递过去,然后通过地址间接修改原内容)

数组传递

开辟堆区空间
malloc
#include <stdlib.h>
void *malloc(size_t size)
功能:开辟堆区空间
参数:开辟堆区空间的大小
返回值:
成功:开辟堆区空间的首地址
失败:NULL
ex: int *p = (int *) malloc (sizeof (int )*10);
定义: 整型 函数名 强转整型 堆区名 空间大小(整型)*10=40
free
功能:释放堆区空间
参数:要释放的堆区空间首地址
返回值:无
ex: free(p); p=NULL;
free(堆区函数名); 函数名清零;
string 函数族
有相同的头文件
strlen
#include<string.h>
功能:计算字符串实际元素个数
参数:字符串的首地址
返回值:字符串实际元素个数
strcpy
#include<string.h>
char *strcpy(char *dest,const char *src);
功能:字符串的复制
参数:dest目标字符串首地址,src原字符串首地址
返回值:目标字符串首地址

会把'\0'一起复制过去
char *strncpy(char *dest, const char *src, size_t n);
功能:字符串的复制
参数:dest目标字符串首地址,src原字符串首地址,size_t n字符个数
返回值:目标字符串首地址

![]()
strcat
#include <string.h>
char *strcat(char *dest, const char *src);
功能:字符串的拼接
参数:dest目标字符串首地址,src原字符串首地址
返回值:目标字符串首地址
strcmp
#include <string.h>
int strcmp(const char *s1, const char *s2);
功能:字符串的比较
参数:两个字符串的首地址
返回值:0 s1==s2
1 s1>s2
-1 s1<s2
递归函数
递推阶段:从原问题出发,按递归公式从未知到已知,最终到达递归终止条件(只需了解)
回归阶段:按递归的终止条件求出结果,逆向逐步带入递归公式,回到原问题求解
结构体
用户自定义的一种数据类型
格式:
struct 结构体名
{
成员变量1;
成员变量2;
成员变量3;
};
eg:
struct ikun
{
int id;
int age;
float height;
char name[33];
};
成员变量类型:基本数据类型(6种)、指针、数组、结构体类型;不能是函数;
结构体变量
格式:struct 结构体名 结构体变量;
1.定义结构体的同时,直接定义结构体变量
struct 结构体名
{
成员变量1;
成员变量2;
成员变量3;
}结构体变量;
struct ikun
{
int id;
int age;
float height;
char name[33];
}ik; //全局变量
struct ikun{
int id;
int age;
float height;
char name[33];
};
int main(int argc, char const *argv[])
{
struct ikun ik; //局部变量
return 0;
}
struct{
int id;
int age;
float height;
char name[33];
}ik;
赋值

2.先定义,再逐个赋值
#include<stdio.h>struct ikun
{
int id;
int age;
float height;
char name[33];
}ik;
int main(int argc, char const *argv[])
{
ik.id=2;
ik.height=188.9;
return 0;
}
3.点等法
#include<stdio.h>
struct ikun
{
int id;
int age;
float height;
char name[33];
};
int main(int argc, char const *argv[])
{
struct ikun ik={
.id=2,
.age=11,
.height=156
};
return 0;
}
访问
printf("%d %.1f\n",ik.id,ik.height);
scanf("%d %f %s",&ik.id,&ik.height,ik.name);
重定义 typedef
typedef int size_t;
int a;====size_t a;
结构体的数据类型名字太长,重新取个别名;
typedef struct ikun
{
}KK; //结构体名改为KK
1.定义的同时重定义

2.先定义,再重定义

结构体数组
结构体类型相同的变量组成的数组
1.定义结构体的同时,定义结构体数组
struct star
{
int id;
int age;
float height;
char name[33];
}s[3];
2.先定义结构体,在定义结构体数组

初始化
struct star{
int id;
int a;
float h;
char name[33];
}s[2]={
{1,18,136,"abc"},
{2,22,123,"qwe"}
};


结构体指针
指针结构体变量的指针
格式:

赋值
指针变量名->成员变量名
p->id=5;
p->h=23.3;
strcpy(p->name,"abc");
(*p).id=6;
结构体大小

共用体
不同类型的成员变量共用一块地址空间
union 共用体名
{
成员变量;
};
union 共用体名 变量名;

特点:
- 成员变量共用同一块地址空间
- 成员变量赋值以最后一次为准
- 共用体的大小为成员变量中最大的为准
枚举
格式:
enum 枚举名
{
value 1,
value 2,
value 3,
.......
};
#include<stdio.h>
enum val
{
a,
b,
c,
};
int main(int argc, char const *argv[])
{
printf("%d %d %d\n",a,b,c); //未赋值时,从0开始
return 0;
}
存储类型
auto static
static修饰的变量会被存放在静态区

生命周期为整个程序
修饰局部变量,和普通的局部变量作用域没区别,但是生命周期被延长至整个程序
修饰全局变量,限制在本文件使用


被static修饰的变量

被折叠的 条评论
为什么被折叠?



