大一C语言知识点
形参,实参:
形参就是
比如void dfs(int x,int fa) x 和 fa 就是形参
实参就是:
int main()
{
int a,b; a和b就是实参,全局变量也是
}
形参:
调用函数时,形参会被分配一个新的内存空间,实参的值就会被“复制”进去,
让它在被调函数中参与运算。而实参本身不参与这个运算,它仅仅起到一个传递值的作用(不过在C++中可以用&改变实参的值)。
如果参数的形式是指针,那么“复制”的就是地址。
传值调用的形参只有在被调用时才被创建(分配存储单元)。
实参:实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。
重点:形参和实参虽然可以同名,但它们之间是相互独立的,互不影响,因为实参在函数外部有效,而形参在函数内部有效。
scanf:
/*
scanf第二个参数需要返回一个地址
即scanf 第二个参数 是地址
*/
一维数组与地址关系:
/*
重点:int a[6]; 下标表示 (0~5)
数组名为指向首地址的指针:
a 就是 a[0]的地址,
a+i (i称为偏移量) 就是a[i]的地址
*a取了间访,为第一个元素的内容,即a[0],*a+i 是 a[i]元素的值
输入是有两种方法
1.for(int i=0;i<6;i++) scanf("%d",&a[i]); 2.for(int i=0;i<6;i++) scanf("%d",a+i);
*/
二维数组与地址关系:
/*
二维数组需要通过两次间接引用才能取到对应的元素,一次间接引用依旧是地址。
int a[3][4] 下标范围(0~2,0~3)
a表示&a[0][0]
*a+i写完整为*(a+0)+i,表示&a[0][i]
*(a+i)写完整为*(a+i)+0,表示&a[i][0]
*(a+i)+j表示&a[i][j]
a[i]表示&a[i][0]
a[i]+j表示&a[i][j]
**a写完整为*(*(a+0)+0),表示a[0][0]
**(a+i) 相当于*(*(a+i) +0),表示a[i][0]
*(*a+i) 相当于*(*(a+0)+i),表示a[0][i]
*(*(a+i)+j)表示a[i][j]
*a[i]表示a[i][0]
*a[i]+j表示a[i][j]
a[3][1] 为第4行第2列的元素
*(a[3]+1)相当于a[3][1],为第4行第2列的元素
引用二维数组 a 第 i 行、j 列的元素(i、j 为 0 表示第 1 行、第 1 列),可以写 作 *(*(a+i-1)+j-1) 或 a[i-1][j-1] 。
数组声明为“int a[6][6];”,表达式“*a+i”是指 第 1 行第 i+1 个元素的地址、第 i+1 个元素的地址、 *(a+i)是指 第 i+1 行第 1 个元素的地址、**a 又是指 a[0][0]。
关于二维数组地址的加减 : 重点理解每行3个,下下面的图也能为此说明
二维数组中,行下标界可以省,列下标界不能省。原因是二维数组是按照行进行保存的,要正确取出某一行,需要知道该行中有几个元素(即共有几列)
(6条消息) 定义二维数组时,为什么二维数组行可省列不可省_晓龙coding的博客-CSDN博客
*/
各个类型的长度(又称存储空间,sizeof(类型)的值),范围
/*
short int 是2字节
int 和 unsigned int 就是4字节
*/
运算符优先级
/*
类似与 ++x||++y&&++z == ++x||(++y&&++z)这玩意的计算
++x(||&&):先x+=1再判断。
x++(||&&):先判断再x+=1
++x||++y&&++z:=(++x)||(++y&&++z)
先给x += 1,若x等于0,计算右边,给 y+= 1后,若y不为0整个表达式不为0,否则整个表达式为0,再计算后面,给 y+= 1后,若y不为0整个表达式不为0,否则整个表达式为0;
x++&&--y&&z--||--x = (x++&&--y&&z--) || (--x)
先看x 是否为0,如果不为0,x +=1;计算右边,先给y-=1,若不为0,计算右边,判断z是否为0,不为0,表达式(x++&&--y&&z--)值为1,z-=1;
若(x++&&--y&&z--) 为0,判断(--x),不必多说
自增自减运算符和间访运算符的优先级:自增自减运算符高于间访运算符。
c=*++p;执行过程是 先++p,再*p,最后*p赋值给c
c=*p++;执行过程是,先*p,再*p赋值给c,最后p++
*/
指针与区间:
一级指针的类型:int*,char*,long long*(这些是数据类型,int,char,long long这些都是数据类型)
指针所存的内容是地址,但是指针有自己的地址:
间接运算符:*与指针类型区分。
我们跟多用的是内容。所以间接运算符是获取所指向指针的内容。
int *p=&a; int b=*p; a和b是相等的
二级指针:int**,char**,long long**(专门指向一级指针的地址,三级指针指向二级指针的地址,同理)
int a=10,*b=&a,**c=&b;
这里等价:int a=10,int* b=&a,int** c=&b;
故b指针指向a的地址,b和&a是相等的
c指针指向b指针的地址,c和&b是相等的
则*c和b是相等的
*b和a是相等的
**c和a是相等的
指针与函数形参的结合:
void work(int* p) { *p=5; } int main() { int a; work(&a); cout<<a; return 0; }
(a输出5)
始终是以地址进行传输,改的是地址代表的内容,类似于全局变量吧,还是很妙的
malloc、free函数:
个人认为malloc的用处是让一个普通指针变成一维数组来使用,free便是释放空间,消除这个被分配空间的数组
malloc(n*sizeof(类型)):动态分配n个类型数据的空间
malloc返回值:该函数返回一个指针 ,指向已分配大小的内存。如果请求失败,则返回 NULL。
free(指针):释放之前调用 calloc、malloc 或 realloc 所分配的内存空间
以int类型为例 int *p; p=(int*)malloc(n*sizeof(int)); 必须要有强制转换 for(int i=0;i<n;i++) scanf("%d",&p[i]); for(int i=0;i<n;i++) printf("%d\n",p[i]); free(p);
c语言结构体:
有两种定义方式:
1. struct student { }; struct student a[100]; 2. typedef struct student { }STU; STU a[100];
间接引用->:专门为 结构体指针 准备,不需要取间便可以直接指向结构体内的成员名.
struct student { char na[100]; int sc; }; struct student a,*p; p=&a; 则:a.sc==(*p).sc==p->sc;
a.成员名==(*p).成员名==p->成员名
间接引用->的优先级是要高于自增自减运算符:
struct student { char na[100]; int sc; }; struct student a[100], *p; p=a; (++p)->sc: 先让 p 指向a的下一个地址,再取成员 sc 的值,()不能省 (p++)->sc:先取成员 sc 的值,再指向a的下一个地址
结构体内存大小,即sizeof(结构体):
结构体的内存大小一定是最大成员大小的倍数
如:
struct node { char a; ll b; ll c; }; 最大的就是 long long 类型 原本大小是:1+8+8=17 但是要符合最大成员内存大小的倍数就是:3*8=24
文件:
文件的读写
x+的意义是让文件 读写都行
文件几个函数:
remove(文件名) 删除这个文件
rename(旧文件名,新文件名) 改名
feof(FILE* fp) 当读入到文件结束标识符时,该函数返回一个非零值,否则返回零。
fclose(FILE* fp) 关闭这个文件,一定要写
细琐/小知识点:
'\0'为空字符,是字符类型数组初始化时放入的默认值
C 库函数 char *strcpy(char *dest, const char *src) 把 src 所指向的字符串复制到 dest。
C 库函数 char *strcat(char *dest, const char *src) 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
函数abs是对整数取绝对值,fabs是对浮点数取绝对值
char str[]='abc'(×)char str[]="abc"(√)