一、命令行参数
int main(int argc, char const *argv[])
{
return 0;
}
argv:就是一个指针数组,里面存放的是命令行传递的字符串
argc:表示argv指针数组里面存储数据的个数,即命令行传递字符串的个数
int main(int argc, char const *argv[])
{
printf("argv[0]=%s,argv[1]=%s ,argc=%d\n",argv[0],argv[1],argc);
return 0;
}
二、 函数
1.定义
定义:一个完成特定功能的代码模块可以实现代码的复用
格式:
存储类型数据类型函数名(参数列表)
{
//功能代码函数体
}
2.调用
使用:函数调用
函数调用:函数名(参数);
3.三要素
函数的三要素:功能参数 返回值
#include <stdio.h>
#include <string.h>
//输出 今天不下雨了
int fun()
{
printf("今天不下雨了\n");
}
int main(int argc, char const *argv[])
{
fun();//函数的调用
fun();//函数的调用
fun();//函数的调用
fun();//函数的调用
fun();//函数的调用
return 0;
}
4.函数有以下几种情况:
1)有参数的话正常在小括号中写参数
参数分类:形参实参
形参:在定义函数时写在小括号中的参数,接收实参传递的数据
实参:调用时写在小括号的参数,给形参传递数据
#include <stdio.h>
#include <string.h>
//计算两个数的和
int fun(int a,int b)//形参
{
printf("a+b=%d\n",a+b);
}
int main(int argc, char const *argv[])
{
fun(1,2 );//实参
fun(100,2 );//实参
return 0;
}
2) 没有参数:参数列表可以省略,也可以用void
#include <stdio.h>
#include <string.h>
//计算两个数的和
int fun(void)//形参
{
}
int main(int argc, char const *argv[])
{
fun();//实参
return 0;
}
3) 有返回值:要根据返回值的数据类型定义函数的数据类型
#include <stdio.h>
#include <string.h>
//计算两个数的和
int fun(void)//形参
{
int a=101;
return a;
}
int main(int argc, char const *argv[])
{
int ret= fun();
printf("%d\n",ret);
return 0;
}
4)没有返回值:数据类型为void,函数内部没有return 语句。
void fun(void)//没有返回值
{
int a=101;
printf("12345678");
}
5) 定义子函数时可以直接定义在主函数上面,如果定义在主函数下面需要提前声明函数
函数的声明:存储类型数据类型函数名(参数列表);
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
int fun(void);
fun();
return 0;
}
int fun(void)//形参
{
int a=101;
printf("12345678");
}
5.return的作用:
1. 返回return右边的数据给外界
2. 阻断代码的执行
练习:
8.若有以下说明和语句,int c[4][5],(*p)[5];p=c;能正确引用c数组元素的是_____.
A) p+1 B) *(p+3) C) *(p+1)+3 D) *(p[0]+2)
答案:D
练习:
编写一个函数,函数的2个参数,第一个是一个字符,第二个是一个char *,
功能:返回字符串中该字符的个数。
#include <stdio.h>
#include <string.h>
// 计算字符串中字符的个数
int fun(char s, char *str) // str:字符串 s:字符
{
int i = 0;
while (*str) //*str!='\0'
{
if (*str == s)
i++;
str++;
}
return i;
}
int main(int argc, char const *argv[])
{
char a='a';
char s[32]="abc";
printf("%d\n", fun(a,s));
return 0;
}
练习:
返回字符串中某一字符在此字符串中首次出现的位置下标
6.函数传参
1. 值传递
实参-->形参(单向传递)修改形参不会影响实参
#include <stdio.h>
#include <string.h>
// 计算字符串中字符的个数
void fun(int a) // str:字符串 s:字符
{
a = 200;
}
int main(int argc, char const *argv[])
{
int a = 10;
fun(a);
printf("%d\n", a);
return 0;
}
2.地址传递
双向传递形参的改变会影响实参
#include <stdio.h>
#include <string.h>
// 计算字符串中字符的个数
void fun(int *a, int *b) // str:字符串 s:字符
{
int c = *a;
*a = *b;
*b = c;
printf("子函数:a=%d b=%d\n",*a,*b);
}
int main(int argc, char const *argv[])
{
int a = 10;
int b = 20;
fun(&a,&b);
printf("主函数:a=%d b=%d\n",a,b);
return 0;
}
3. 数组传递
和地址传递一样
#include <stdio.h>
#include <string.h>
void fun(int a[],int n){//int *p
for (int i = 0; i < n; i++)
{
printf("%d ",a[i]);
}
}
int main(int argc, char const *argv[])
{
int a[3]={1,2,3};
fun(a,3);
return 0;
}
堆区空间
malloc
头文件: #include <stdlib.h>
void *malloc(size_t size);
功能:开辟堆区空间
参数:size:开辟空间的大小(字节)
返回值:
成功:返回开辟成功的首地址
失败:NULL;
int *p = (int *)malloc(sizeof(int) * 4);
if (p == NULL)
{
printf("err\n");
}
printf("%p\n", p);
mallocfree搭配使用
free
#include <stdlib.h>
void free(void *ptr);
功能:释放堆区空间
参数:ptr:要释放空间的地址
返回值:无
void *p = malloc(sizeof(int) * 4);
if (p == NULL)
{
printf("err\n");
}
printf("%p\n", p);
free(p);
p=NULL;
堆和栈的主要区别:
1、栈由系统自动分配,而堆是人为申请开辟;
2、栈获得的空间较小,而堆获得的空间较大;
3、栈由系统自动分配,速度较快,而堆一般速度比较慢;
4、 栈是连续的空间,而堆是不连续的空间是随机分配的。
5、
注意:
1.手动开辟堆区空间,要注意内存泄漏
当指针指向开辟堆区空间后,又对指针重新赋值,则没有指针指向开辟堆区空间,就会造成内存泄漏
2. 使用完堆区空间后及时释放空间
练习:
void fun(char *p) //p=NULL
{
p = (char *)malloc(32);
strcpy(p, "hello");
}
int main()
{
char *m = NULL;
fun(m);
printf("%s\n", m);// 段错误
return 0;
}
1. 使用返回值
char *fun() //p=NULL
{
char *p = (char *)malloc(32);
strcpy(p, "hello");
return p;
}
int main()
{
char *m =fun();
printf("%s\n", m);// hello
free(m);
m=NULL;
return 0;
}
2. 传递参数
void fun(char **p) //p=NULL
{
*p = (char *)malloc(32);
strcpy(*p, "hello");
}
int main()
{
char *m = NULL;
fun(&m);
printf("%s\n", m);// hello
free(m);
m=NULL;
return 0;
}