C语言再学习 -- 关键字return和exit ()函数

Posted 聚优致成

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言再学习 -- 关键字return和exit ()函数相关的知识,希望对你有一定的参考价值。

终于到了最后一个关键字 return 了。感觉时间过的飞快,转眼间又是一年,如果时间可以 return 就好了。


一、return 介绍

参看:C语言中return 用法
1.含义: 
return 表示从被调函数返回到主调函数继续执行,返回时可附带一个返回值返回值可以是一个常量,变量,或是表达式。

2.作用: 结束正在运行的函数,并返回函数值。

3.返回值:
计算结果表示函数执行的顺利与否( -1、 0)
返回值可以为各种数据类型, 如: int, float, double, char, a[](数组), *a(指针) ,结构或类( c++)
返回类型规定了 return后面所加的量的类型,如果返回类型声明为void,则不需要返回值。 

void Main( )  //程序入口只可以声明为void和int的返回

//不需要返回值就OK
void mm( )

return; //有些时候,在 void的方法中,你需要跳出它,可以直接用return而不能加任何量在后面
int cc( )

return 321; //因为返回类型声明为int,所以返回一个整数
char* msmsm( )

return“asdfhasjghdg”; //因为返回类型声明为 char*,所以返回一个字符串


4. 返回值用法:
1)返回函数值

例1:一个计算阶层的函数:

#include <stdio.h>

int foo (int n)

	int p = n + 2;
	return p;


int main (void)

	printf ("p = %d\\n", foo (1));
	return 0;

输出结果:
p = 3 
return的功能为返回函数的值。


2)返回一个函数的值,并且跳出这个函数
例2: 

#include <stdio.h>

int foo (int n)

	if (n == 1)
	
		return 1;
	

	else if (n == 2)
	
		return 2;
	
	else  
	
		return 3;
	


int main (void)

	printf ("p = %d\\n", foo (13));
	return 0;

输出结果:
p = 3 
说明:当参数为1时函数返回值为1并且跳出函数,当参数为2时函数返回值为2并且跳出函数,当函数为其他值时返回3。


3)跳出循环并且跳出函数,同时返回函数值
例3:另一个计算阶层的函数:

#include <stdio.h>

int foo (int n)

	int i = 0;
	int j = 0;
	for (i = 0; i < 10; i++)
	
		j += i;

		if (i == n)
		
			return j;
		
	


int main (void)

	printf ("p = %d\\n", foo (7));
	return 0;

输出结果:
p = 28
return的功能为跳出循环并且跳出函数,再返回函数值。

说明:
1)一个入口一个出口。
2)在函数中, 如果碰到return 语句, 那么程序就会返回调用该函数的下一条语句执行,也就是说跳出函数的执行,回到原来的地方继续执行下去。但是如果是在主函数中碰到 return语句,那么整个程序就会停止,退出程序的执行

#include <stdio.h>

 void foo (void)

	printf ("hello world!\\n");
	return;
	printf ("11111111111\\n"); 


int main (void)

	foo ();
	printf ("welcome beijing!\\n");
	return 0;
	printf ("22222222222\\n");

输出结果:
hello world!
welcome beijing!
3)void main( ) ,其实这是错误的 。若希望程序拥有很好的可移植性,请一定要用 int main ( ) 

注意:如果没有写明返回值,一般默认为 int 类型。

main (void)  
  
...  
    return 0;  
  

4)main 函数的返回值用于说明程序的退出状态。如果返回 0,则代表程序正常退出,否则代表程序异常退出。
5) 如果函数名前有返回类型定义,如int,double等就必须有返回值,而如果是 void型, 则可以不写return, 但这时即使写了也无法返回数值。
a.  非void型

#include <stdio.h>

int foo (int n)

	int p = n + 2;
	return p;


int main (void)

	printf ("p = %d\\n", foo (1));
	return 0;

输出结果:
p = 3 

b.  void型
void f2( )

    inti=1;
    //return;//这样也可以,不要这一句也可以
return 关键字第一个作用,也就是他的真实作用返回值,这个返回值是和函数的类型有关的,函数的类型是什么,他的返回值就是什么。
比方主函数 int main().... 这里就必须有一个return,只有void时可以不用返回值。
功能函数

int fun()

    return 1;
这个时候fun函数的作用就是返回一个int 类型的值,可以直接拿来用比方 int a=fun ( );
这里就相当于int a=1;
另外一个作用return后面的语句不会执行, 我们可以用它来结束程序比方找出三个数种最大的一个数

void main

int a, b, c;
if( a>b)
if(b>c)

return printf("最大值为%d", a);

.....
在这里if( b>c)我们就可以直接得出a是最大了, 就没必要执行下面的语句了, return 这里就起到了终止语句的作用了等用得多了还会有些妙用的,你要自己慢慢体会。
int f(int a)

if(a<0) return -1;
else if(a==0) return 0;
else return 1;

int b=f(c);
c 的值不同 函数返回给 b 值也就不同我认为返回值是函数与外界的接口之一至于所谓的状态,应该是由人来规定的。比如当返回值为 0 我们就知道 f( ) 的传入值 c 是等于 0 的至于是 return 值 还是 return 表达式都是一个意思,因为表达式最终的值也是由表达式计算的最终结果来存储的返回值就是“函数值”学习学的时候天天都会遇到函数,而函数给一个自变量函数就会有一个函数值对吧。比如说正弦函数sin, sin(x),不同的x值会得到不同的正弦值y=sin(x) 就是将函数值赋值给y,函数运算完毕y就有了一个值c语言函数意思一样的。
#include <stdio.h>

 int  foo (int n)

	return 2 * n;


int main (void)

	int a = foo (5);
	printf ("a = %d\\n", a);
	return 0;

输出结果:
a = 10
return 的作用是结束正在运行的函数,并返回函数值。 return后面可以跟一个常量,变量,或是表达式。函数的定义一般是这样的,例如:
int a( int i)//第一个int是函数的返回值的类型, 也就是return后面跟的值的类型, a是函数的名称, 括号里的是传递给函数的参数, int是参数的类型, i是参数的名字

...//省略函数体内容
return b;//b必须与函数头的返回值一致(此处为int型)
函数括号里的参数也可以为变量或能算出值的表达式以上就是一个基本的函数, 一般的函数都有返回值, 也就是return后面跟的值,返回值可以为各种数据类型,如: int, float, double, char, a[](数组), *a(指针),结构或类( c++)

但不是所有函数都有返回值, 如果某个函数无返回值, 那么返回值的位置则为“void”关键字,此时函数体中无返回值,即无 return 的值。但是函数中也可出现 return,即一个空的 return句子,其作用是使函数立即结束,如

#include <stdio.h>

 void foo (void)

	printf ("hello world!\\n");
	return;
	printf ("11111111111\\n"); 


int main (void)

	foo ();
	printf ("welcome beijing!\\n");
	return 0;
	printf ("22222222222\\n");

输出结果:
hello world!
welcome beijing!

二、return 进阶

C语言中的错误处理,如:

int main()

	//...
	if(判断)
	
	return -1;//返回-1,表示程序不正常结束
	
	
	return 0;//返回0,表示程序正常结束

C语言中通过使用返回值来表示是否出错,根据返回值来进行具体的错误处理。

错误表示的一般规则
C语言中通过使用返回来表示是否出错,根据返回值来进行具体的错误处理一般规则:
(1)如果返回值类型时int类型,并且返回的值不可能是负数时,则使用返回值-1代表出错,其他数据表示正常返回。

#include <stdio.h>

int rand_num(void)

	srand(time(0));
	int res=rand()%10+1;
	return 5==res?-1:res;


int main (void)

	printf("生成的随机数是:%d\\n",rand_num());
	return 0;

输出结果:
生成的随机数是:-1
(2)如果返回值类型时int类型,并且返回的值可能是负数时,则需要使用指针取出返回值的数据,返回值仅仅表示是否出错,-1表示出错,0表示正常返回

#include <stdio.h>

int max(int i,int j,int* pi)//指针做形参

	if(i==j)
	
		return -1;
	
	*pi=i>j?i:j;


int main (void)

  int res=0;
  max(10,30,&res);
	printf("最大值是%d\\n",res);
	return 0;

输出结果:
最大值是30
(3)如果返回值类型是指针类型,则返回值NULL代表出错

#include <stdio.h>

char* judge (const char* pc)

	if (!strcmp (pc, "error"))
	
		return NULL;
	
	return "ok";


int main (void)

	printf("返回的字符串是:%s\\n",judge ("let me give you some color see see"));
	return 0;

输出结果:
返回的字符串是:ok
(4)如果不考虑是否出错,返回值类型使用void即可

#include <stdio.h>

void print(char* pc)

	printf("传入的字符串是:%s\\n",pc);


int main (void)

	print("no zuo no dear");
	return 0;

输出结果:
传入的字符串是:no zuo no dear


三、exit ( ) 函数介绍

函数原型:

#include <stdlib.h>

void exit(int status)

参数:
status -- 返回给父进程的状态值。

函数作用:

关闭所有文件,终止正在执行的进程


exit(0)表示正常退出,
exit(x)(x不为0)都表示异常退出,这个x是返回给操作系统(包括UNIX,Linux,和MS DOS)的,以供其他程序使用。

通常情况下,程序成功执行完一个操作正常退出的时候会带有值 EXIT_SUCCESS。在这里,EXIT_SUCCESS 是宏,它被定义为 0。如果程序中存在一种错误情况,当您退出程序时,会带有状态值EXIT_FAILURE,被定义为 1


标准C中有 EXIT_SUCCESS 和 EXIT_FAILURE 两个宏,位于 /usr/include/stdlib.h
#define EXIT_FAILURE    1   /* Failing exit status.  */
#define EXIT_SUCCESS    0   /* Successful exit status.  */

//示例一 一般函数
#include <stdio.h>
#include <stdlib.h>

int main ()

   printf("程序开头....\\n");
   
   printf("退出程序....\\n");
   exit(0);

   printf("程序结尾....\\n");

   return(0);

输出结果:
程序开头....
退出程序....

//示例二 
#include <stdio.h>
#include <stdlib.h>

main()

   int i = 20;
   int j = 5;
   int q;
 
   if( j == 0)
      fprintf(stderr, "除数为 0 退出运行...\\n");
      exit(EXIT_FAILURE);
   
   q = i / j;
   fprintf(stderr, "q 变量的值为: %d\\n", q);

   exit(EXIT_SUCCESS);

输出结果:
q 变量的值为: 4


四、关键字 return 和 exit ()函数区别

参看:exit和return的区别

主要有几下几个不同点:
1. return 返回函数值,是关键字;exit 是一个函数。
2. return 是语言级别的,它表示了调用堆栈的返回;而 exit 是系统调用级别的,它表示了一个进程的结束
3. return 是函数的退出(返回);exit 是进程的退出。
4. return 是 C 语言提供的,exit 是操作系统提供的(或者函数库中给出的)。
5. return 用于结束一个函数的执行,将函数的执行信息传出个其他调用函数使用;exit 函数是退出应用程序,删除进程使用的内存空间,并将应用程序的一个状态返回给 OS,这个状态标识了应用程序的一些运行信息,这个信息和机器和操作系统有关,一般是 0 为正常退出,非 0 为非正常退出。通常情况:exit(0)表示程序正常, exit(1)和exit(-1)表示程序异常退出,exit(2)表示系统找不到指定的文件。
6. 非主函数中调用 return 和 exit 效果很明显,但是在 main 函数中调用 return 和 exit 的现象就很模糊,多数情况下现象都是一致的。


下面来分析下,return 是语言级别的,它表示了调用堆栈的返回;而 exit 是系统调用级别的,它表示了一个进程的结束这句话是什么意思。

我们之前有讲过值传递和址传递的,参看: C语言再学习 -- 值传递,址传递,引用传递

问题二:

char *GetMemory( void )  
  
 char p[] = "hello world";  
 return p;  
  
void Test( void )  
  
 char *str = NULL;  
 str = GetMemory();  
 printf( str );  
  

请问运行 Test 函数会有什么样的结果? 
答:可能是乱码。
因为 GetMemory 返回的是指向“栈内存”的指针,该指针的地址不是 NULL,但其原现的内容已经被清除,新内容不可知。

char p[] = "hello world";
return p;
p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其根源在于不理解变量的生存期。

#include <stdio.h>  
char* fa(char* p_str)//指针做形参可以使用调用函数的存储区  
  
    char* p=p_str;  
    p="hello world";  
    return p;  
  
  
int main()  
  
    char* str=NULL;  
    printf("%s\\n",fa(str));  
    return 0;  
  

所以说,return 语句不可返回指向“栈内存”的“指针”,因为该内存在函数体结束时被自动销毁。


再看另外一句话,非主函数中调用 return 和 exit 效果很明显,但是在 main 函数中调用 return 和 exit 的现象就很模糊,多数情况下现象都是一致的。

按照 ANSI C,在最初调用的main()中使用return和exit()的效果相同。但要注意这里所说的是“最初调用”。如果main()在一个递归程序中,exit()仍然会终止程序;但return将控制权移交给递归的前一级,直到最初的那一级,此时return才会终止程序。此外,return和exit()的另一个区别在于,即使在除main()之外的函数中调用exit(),它也将终止程序。

//最初调用的 main 函数中
#include <stdio.h>
#include <stdlib.h>
void func(void)

	printf("2\\n");
	exit(0); //等同于 return ; 即使在被调用函数中使用,它也将终止程序
	printf("3\\n");

int main()

	printf("1\\n");
	func();
	printf("4\\n");		//exit 以后的都不存在
	return 0;

输出结果:
1
2
//递归函数
#include <stdio.h>
int fei(int num)

	if(num<=1)
	
		return 1; //return将控制权移交给递归的前一级,直到最初的那一级
	
	return fei(num-2)+fei(num-1);//这个真的不用明白他为什么这么算


int main()

	int num=0;
	printf("请输入一个编号:");
	scanf("%d",&num);
	int num1=fei(num);
		printf("编号为%d的数字是%d\\n",num,num1);
	return 0;

输出结果:
请输入一个编号:12
编号为12的数字是233
//递归函数
#include <stdio.h>
#include <stdlib.h>
int fei(int num)

	if(num<=1)
	
		//return 1;
		exit (0); //exit()仍然会终止程序
	
	return fei(num-2)+fei(num-1);//这个真的不用明白他为什么这么算


int main()

	int num=0;
	printf("请输入一个编号:");
	scanf("%d",&num);
	int num1=fei(num);
		printf("编号为%d的数字是%d\\n",num,num1);
	return 0;

输出结果:
请输入一个编号:12
(会结束退出)

五、扩展,进程终止

参看:exit和return的区别

进程开始:

C程序是从main函数开始执行, 原型如下: int main(int argc, char *argv[]); 通常main的返回值是int型, 正确返回0。 

进程终止: 

C程序的终止分为两种: 正常终止和异常终止。正常终止分为: return, exit, _exit, _Exit, pthread_exit异常终止分为: abort, SIGNAL, 线程响应取消

主要说一下正常终止的前4种, 即exit系列函数。

1、exit 函数

#include <stdlib.h>  
void exit(int status);

exit(0)表示正常退出,
exit(x)(x不为0)都表示异常退出,这个x是返回给操作系统(包括UNIX,Linux,和MS DOS)的,以供其他程序使用。

详细的上面都已经讲的很明白了。它的作用是:exit 是系统调用级别的,它表示了一个进程的结束

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int main()

	//使用vfork函数创建子进程
	pid_t pid=vfork();
	if(-1==pid)
	
		perror("pid"),exit(-1);
	
	if(0==pid)
	
		printf("子进程%d开始运行\\n",getpid());
		sleep(2);
		printf("子进程结束\\n");
		//子进程不退出,结果不可预知
		exit(0);//终止子进程
	
	printf("父进程%d开始运行\\n",getpid());
	printf("父进程结束\\n");
	return 0;

输出结果:
子进程2944开始运行 (等待2秒)
子进程结束
父进程2943开始运行
父进程结束

2、_exit 函数

使用 _exit() /_Exit()函数终止进程
#include <unistd.h>
void _exit(int status);   => UC函数
#include <stdlib.h>
void _Exit(int status);   =>标C函数

函数功能:
这两个函数都用于立即终止正在调用的进程,参数作为返回值返回给父进程来代表进程的退出状态可以使用wait系列函数获取退出状态。


_exit() 函数:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;
exit()   函数:则在这些基础上作了一些包装(包括调用执行各终止处理程序,关闭所有标准I / O流等)),在执行退出之前加了若干道工序。
exit() 函数与 _exit() 函数最大的区别就在于 exit() 函数在调用 exit 系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件。

举个简单例子:

//示例一 exit 函数
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main (void)

	printf ("1111111111\\n");
	printf ("2222222222");  //注意这里没有加 '\\n'
	exit (0);
	return 0;

输出结果:
1111111111
2222222222
//示例二 _exit 函数
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main (void)

	printf ("1111111111\\n");
	printf ("2222222222"); //注意这里没有加 '\\n',如果加上'\\n'则结果不同
	_exit (0);  //_exit()函数无法输出缓冲区中的记录
	return 0;

输出结果:
1111111111


参看:exit()和_exit()函数

在Linux的标准函数库中,有一种被称作“缓冲I/O(buffered I/O)”的操作,其特征就是对应每一个打开的文件,在内存中都有一片缓冲区。
每次读文件时,会连续读出若干条记录,这样在下次读文件时就可以直接从内存的缓冲区中读取;同样,每次写文件时,也仅仅是写入内存中的缓冲区,等满足了一定的条件(如达到一定数量或遇到特定字符等,最典型的就是咱们的vim中使用的:w命令),再将缓冲区中的内容一次性写入文件。
这种技术大大增加了文件读写的速度,但也给咱们的编程带来了一些麻烦。比如有些数据你认为已经被写入到文件中,实际上因为没有满足特定的条件,它们还只是被保存在缓冲区内,这时用_exit()函数直接将进程关闭掉,缓冲区中的数据就会丢失。因此,若想保证数据的完整性,最好使用exit()函数。

下面的例子,也正好说明了这一点。

//示例三 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void show(void)

	printf("我就是注册过的函数\\n");

int main()

	//使用atexit函数进行注册
	atexit(show);
	printf("main函数开始执行\\n");
//	exit(100);//终止进程
//	_exit(100);//立即终止
	_Exit(100);//立即终止
	printf("main函数结束\\n");
	return 0;

输出结果:
main函数开始执行


这里涉及到 atexit 函数

#include <stdlib.h>
int atexit(void (*function)(void));

函数功能:

主要用于按照参数指定的函数进行注册,注册过的函数会在正常进程终止时被调用。

atexit 终止处理程序:ISO C规定,一个进程最多可登记32个终止处理函数,这些函数由 exit 按登记相反的顺序自动调用如果同一函数登记多次,也会被调用多次。

#include <stdlib.h>
#include <stdio.h>
static void my_exit1 (void)

    printf ("first exit handler\\n");

static void my_exit2 (void)

    printf ("second exit handler\\n");

int main()

    atexit (my_exit2);
    atexit (my_exit1);
    atexit (my_exit1);
    printf ("main is done\\n");
    return 0; // 相当于exit(0)

输出结果:
main is done
first exit handler
first exit handler
second exit handler

还有一句话,可以使用wait系列函数获取退出状态,怎么实现?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()

	//1.创建子进程
	pid_t pid=fork();
	if(-1==pid)
	
		perror("fork"),exit(-1);
	
	//2.子进程工作10秒后终止
	if(0==pid)
	
		printf("子进程%d开始运行\\n",getpid());
		sleep(2);
		printf("子进程结束\\n");
		_exit(100);
	
	//3.父进程等待子进程结束
	printf("父进程开始等待\\n");
	int status=0;
	int res=wait(&status);
	printf("等待结束,status=%d,res=%d\\n",status,res);
	//判断子进程是否正常终止
	if(WIFEXITED(status))//wait exit end
	
		//获取子进程退出状态信息
		printf("子进程的退出码是:%d\\n",WEXITSTATUS(status));//wait exit status
	
	return 0;

输出结果:
父进程开始等待
子进程3156开始运行
子进程结束
等待结束,status=25600,res=3156
子进程的退出码是:100

这里涉及到 wait函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);

函数功能:

主要用于挂起正在运行的进程进入等待状态,直到有一个子进程终止参数主要用于获取终止进程的退出状态成功返回终止进程的进程号,失败返回-1

WIFEXITED(*status)  判断是否正常终止
WEXITSTATUS(*status)  获取进程退出状态信息


3、pthread_exit 函数

pthread_exit函数
#include <pthread.h>
void pthread_exit(void *retval);

函数功能:

主要用于终止正在运行的线程,通过参数 retval 来带出线程的退出状态信息,在同一个进程中的其他线程可以通过调用 pthread_join 函数来获取退出状态信息。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* task(void* p)

	static int i=0;
//	int i=0;
	for(i=0;i<=100;i++)
	
		if(i==10)
		
			pthread_exit((void*)&i);
		
		printf("子进程中:i=%d\\n",i);
	

int main()

	//1.启动线程打印1~100之间的数
	pthread_t tid;
	pthread_create(&tid,NULL,task,NULL);
	//2.等待子进程结束,并且获取返回值
	int* pi=NULL;
	pthread_join(tid,(void**)&pi);
	printf("子线程中变量的值是:%d\\n",*pi);
	return 0;

编译:gcc test.c -pthread
输出结果:
子进程中:i=0
子进程中:i=1
子进程中:i=2
子进程中:i=3
子进程中:i=4
子进程中:i=5
子进程中:i=6
子进程中:i=7
子进程中:i=8
子进程中:i=9
子线程中变量的值是:10

4、abort 函数

功能:异常终止 一个进程
用法: void abort(void);
头文件:#include <stdlib.h>
说明:abort函数是一个比较严重的函数,当调用它时,会导致程序异常终止,而不会进行一些常规的清除工作,比如释放内存等。

#include <stdio.h>
#include <stdlib.h>

int main (void)

	puts( "About to abort....\\n" );
	abort();

	puts( "This will never be executed!\\n" );
	return 0;

输出结果:
About to abort....

已放弃 (核心已转储)

六、return 与 break 区别

1、break关键字是结束一个循环,并跳出当前循环体, 继续执行当前循环之后的语句。
2、return关键字是结束一个函数。

#include <stdio.h>

int main (void)

	int i = 0;
	int sum = 0;
	while (1)
	
		sum += i;
		i++;
		if (i == 5)
		
			printf ("sum = %d\\n", sum);
			break;  //结束循环
		
	
	printf ("hello world!\\n");  //继续执行循环之后的语句
	return 0; //结束函数
        printf ("good bye!\\n"); //不在执行

输出结果:
sum = 10
hello world!




以上是关于C语言再学习 -- 关键字return和exit ()函数的主要内容,如果未能解决你的问题,请参考以下文章

C语言中exit(0)与exit(1)有啥区别??

exit() 与 return() 的区别

c语言exit和return有啥区别

C语言异常处理和exit()怎样使用?

退出和返回有啥区别? [复制]

exit与exit,return三者区别(详解)