函数与数组初阶

这篇博客主要介绍了C语言中函数和数组的基础知识,包括零散知识点、随机数与随机种子的概念,以及函数和数组的使用。讲解了函数的调用过程、递归、数组的定义与特性,并给出了多个编程示例,如打印素数、计算数字9出现次数、求阶乘等,帮助读者巩固理解和实践能力。
摘要由CSDN通过智能技术生成

函数与数组

本篇博客总结一下近十余天的学习收获。主要涉及函数以及数组的知识。

零散知识点

1、printf叫作“格式化打印”,print format。%d叫作“格式化字符串”。
2、使用strlen函数时需要包含对应的库函数。C语言内置的库函数其实非常少(几百个)。相比之下,Java、Python等更加现代的语言,支持的库函数要更加丰富和庞大。
3、变量/函数 常见的命名风格
  (a)小驼峰命名法:toGuess
  (b大小驼峰命名法:ToGuess
  ©蛇形命名法:to_guess
  (d)脊柱命名法:to-guess
  (e)匈牙利命名法:iToGuess
C/C++中蛇形命名法也比较常见,其它场景下都是驼峰命名法最常见。
4、计算机中,使用一个整数来表示时间,以1970年1月1日0时0分0秒作为基准时刻。以现在时间减去基准时间的秒数之差表示时间。这就是“时间戳”的概念。
5、C语言中知识goto语句,表示“无条件跳转”。
6、linux发行版:各个公司使用linux免费内核(操作系统的核心功能程序),进行自己的定制化开发,加上自己的一些应用。如:Redhat、Debian、Centos、Ubuntu等。
7、编译器会对编写的代码进行优化:在不改变整体逻辑等价的前提下,调整二进制指令的顺序和内容,让调整后的代码执行效率更高。优化会影响bug定位,故调试的时候需要把优化选项关闭或者级别降低,O0不开,O3最大优化(vs默认没有开优化)。
8、在C语言中,整数/整数 结果仍是整数,小数部分被舍去。Java,C++,Go等语言也是如此。但JavaScript,Python3,Dart等语言1/2=>0.5.

随机数与随机种子

计算机中生成的随机数通常都是“伪随机”。
使用rand()函数生成随机数时,会出现得到的随机数序列是固定的序列的问题,例如第一个元素始终是42,第二个事68,第三个是35…
生成随机数序列的初始值,称为“随机种子”。
故想每次程序启动得到不同的随机数序列,就需要设置不同的随机种子。
一般使用时间作为随机种子,例如:srand(time(0));

函数

函数就是一个可以被重复利用的代码片段,避免重复代码被反复拷贝,让代码更简洁,更容易理解。
函数(不局限在C语言中)大概分为几类:
  1、标准库函数. printf/scanf/strlen/strcmp
  2、第三方库函数. scanf_s Sleep
  3、自定义函数.
函数调用的执行过程:
代码执行到函数调用位置的时候,就会进入到函数内部执行,同时对参数进行赋值,(按照位置顺序,分别把实参赋值(拷贝)给形参)。然后在函数内部按照顺序从上到下执行。遇到return语句,则函数结束。
函数结束之后将回到函数的调用位置,继续往下执行。

嵌套调用:函数里调用别的函数
链式访问:函数的返回值作为其它函数的参数

一个函数可以被调用多次,每次调用的时候,都可以传递不同的参数。
实参和形参的关系,只在参数传递的这一瞬间,用实参对形参进行初始化。
这之后,形参和实参之间没有关系了。

很多编程语言天然就支持函数内部访问函数外部的变量(比如JS,Java算部分支持,C++有特殊手段,变量捕获语法能支持),但是C语言不行,C语言的函数内部只能访问函数中定义的局部变量和全局变量。PS:不建议使用全局变量。
因此,需要使用指针来间接访问外部的变量。

C语言中调用函数时,必须保证函数的定义或者声明在调用位置代码的上方(声明一般放在代码最上方)。一个工程中,函数只能定义一次,但是声明可以有很多次。定义有多份就会编译失败。且由于经常要同时声明多个函数,所以放在一个.h文件中,再通过#include的方式引入到.c文件中。例如:

  #include 从系统目录中查找头文件
  #include “xxx” 从当前项目目录中查找头文件,再从系统目录中查找头文件

#include本质是“文本替换”,即拷贝替换。

可以使用
  #ifdef TEST_H_
  #define TEST_H_
  //函数的声明
  int Add(int x,int y);
  #endif
防止头文件被重复包含(不建议这么写了,太麻烦)。

#pragma once这种写法可以起到一样效果,简单且不容易错。

递归即函数调用其本身。调试递归程序,必须要重点关注函数的“调用栈”。
不使用循环/不创建局部变量实现求阶乘→递归(特别适用动态规划问题)

数组

数组批量创建一组相同类型的变量。C++、Java、Go也是入如此,但是Python、JS、PHP不要求相同类型。
C语言中的字符串是一种特殊的“字符数组”,必须是以’\0’(即ASCII值为0的字符)作为结束标记。如果某个字符数组中,没有’\0’,那么这个字符数组就不能称为字符串。PS:字符串长度不计算\0,数组的元素个数计算\0。
一个未初始化的数组,里面的元素内容本质上是VS自动填充的一些无意义的数据。若抛开VS,将是栈空间上的残留值。
在Java或者Go中,对于未手动初始化的变量,会被编译器自动初始化为0值。
定义数组时,[]内只能写常量(字面值、枚举、宏定义),不可使用变量和const。

C语言中,针对数组取下标操作,若越界,产生的效果称为“未定义行为”,运行结果不可预期。数组下标越界,本质上是“访问了非法内存”。

[]操作元素有读写操作,读就是获取变量的值,写就是修改变量的值。

对于一维数组,元素都是处在连续的内存空间上。数组的“维数”可以有很多,但是实际开发中很少使用高维数组。

代码

近期编写的代码如下:

打印素数(穷举法)

打印100~200之间的素数

#include <stdio.h>
#include <windows.h>

#pragma warning(disable:4996)


int main()

{

	int count = 0;
	for (int i = 1; i <= 100; i++){
		if (i % 10 == 9){
			count++;
		}

		if (i / 10 == 9){
			count++;
		}

	}
	printf("%d\n", count);

	system("pause");
	return 0;
}

数字9出现的次数

计算 1 到 100 的所有整数中出现多少个数字9

#include <stdio.h>
#include <windows.h>

#pragma warning(disable:4996)


int main()
{
	int count = 0;
	for (int i = 1; i <= 100; i++){
		if (i % 10 == 9){
			count++;
		}
		if (i / 10 == 9){
			count++;
		}
	}
	printf("%d\n", count);

	system("pause");
	return 0;
}

分数求和

计算1/1-1/2+1/3-1/4+1/5 …… + 1/99 - 1/100 的值,打印出结果

#include <stdio.h>
#include <windows.h>

#pragma warning(disable:4996)

int main()
{
	double result = 0;
	for (int i = 1; i <= 100; i++){
		if (i % 2 != 0){
		result += 1 / (double)i;
		}
		else{
		result -= 1 / (double)i;
		}
	}

	printf("%f\n", result);
	system("pause");
	return 0;
}

求最大值

求10 个整数中最大值

#include <stdio.h>
#include <windows.h>

#pragma warning(disable:4996)


int main()
{
	int arr[] = { 85, 21, 33, 65, 14, 94, 54, 69, 75, 24 };
	int max = arr[0];
	for (int i = 0; i < 10; i++){
		if (arr[i]>max)
			max = arr[i];
	}
	printf("最大值是:%d\n", max);

	system("pause");
	return 0;
}

猜数字游戏

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

#pragma warning(disable:4996)

void Game(){
	int random_num = rand()%100;
	int input;
	while (1){
		printf("请输入数字:");
		scanf("%d", &input);
		if (input > random_num){
			printf("猜大了\n");
		}
		else if (input < random_num){
			printf("猜小了\n");
		}
		else{
			printf("猜对了\n");
			break;
		}
	}
}

int main()
{
	int option = -1;
	srand(time(0));
	while (1)
	{
		printf("***********************\n");
		printf("********1.play*********\n");
		printf("********0.exit*********\n");
		printf("***********************\n");
		scanf("%d", &option);
		if (option == 1){
			Game();
			break;
		}
		else if (option == 0){
			break;
		}
		else{
			printf("输入有误!\n");
			Sleep(300);
			system("cls");
		}
	}
	
	system("pause");
	return 0;
}

交换两个整数

输入正确用户名和密码后附带转圈加载效果,输错3次锁5秒倒计时。

#include <stdio.h>
#include <Windows.h>
#include <math.h>

#pragma warning(disable:4996)

void Swap(int *num1,int *num2){
	int tmp = 0;
	tmp = *num1;
	*num1 = *num2;
	*num2 = tmp;
}


int main(){

	int num1, num2;
	int *p1 = &num1;
	int *p2 = &num2;
	printf("请输入两个数#");
	scanf("%d %d",&num1,&num2);
	printf("交换前:%d %d\n", num1, num2);
	Swap(p1,p2);
	printf("交换后:%d %d\n", num1, num2);

	system("pause");
	return 0;
}

乘法口诀表

打印乘法口诀表,口诀表的行数和列数自己指定

#include <stdio.h>
#include <Windows.h>
#include <math.h>

#pragma warning(disable:4996)

void MulTable(int num){
	for (int i = 1; i <= num; i++){
		for (int j =1; j <= i; j++)
			printf("%d*%d=%d\t", i, j, i*j);
		printf("\n");
	}
}


int main(){

	int num;
	printf("请输入一个数#");
	scanf("%d",&num);
	MulTable(num);

	system("pause");
	return 0;
}

打印一个数的每一位

递归方式实现打印一个整数的每一位

#include <stdio.h>
#include <Windows.h>
#include <math.h>

#pragma warning(disable:4996)

void PrintPlace(int num){
	if (num > 9){
		PrintPlace(num / 10);
	}
	printf("%d\n", num % 10);
}


int main(){

	int num;
	printf("请输入一个数#");
	scanf("%d",&num);
	PrintPlace(num);

	system("pause");
	return 0;
}

求阶乘

递归和非递归分别实现求n的阶乘(不考虑溢出的问题)

#include <stdio.h>
#include <Windows.h>
#include <math.h>

#pragma warning(disable:4996)

int Factorial(int num){
	int result=1;
	if (num == 0){
		return result;
	}
	else{
		for (int i = num; i >= 1; i--){
			result *= i;
		}
	}
	return result;
}

int RecFact(int num){
	int result = 1;
	if (num == 0){
		return result;
	}
	else
		return num*RecFact(num - 1);
}

int main(){

    int num;
    printf("请输入一个数#");
    scanf("%d",&num);
    printf("%d\n", Factorial(num));
    printf("%d\n", RecFact(num));

    system("pause");
    return 0;
}

strlen的模拟

递归和非递归分别实现strlen

#include <stdio.h>
#include <windows.h>

#pragma warning(disable:4996)

int MyStrlen(char* str){
	int ret = 0;
	while (*str != '\0'){
		ret++;
		str++;
	}
	return ret;
}

int MyStrlenRec(char* str){
	if (*str != '\0'){
		return 1+MyStrlenRec(str + 1);
	}
	else{
		return 0;
	}
}


int main(){

	char arr[] = "just a test";
	printf("%d\n", strlen(arr));
	printf("%d\n", MyStrlen(arr));
	printf("%d\n", MyStrlenRec(arr));

	system("pause");
	return 0;
}

字符串逆序(递归实现)

编写一个函数 reverse_string(char * string)(递归实现)
实现:将参数字符串中的字符反向排列。
要求:不能使用C函数库中的字符串操作函数。

#include <stdio.h>
#include <windows.h>

#pragma warning(disable:4996)

void reverse_string(char * string){
	if (*string != '\0'){
		reverse_string(string+1);
		printf("%c", *string);
	}
}


int main(){

	char arr[] = "just a test";
	printf("%s\n",arr);
	reverse_string(arr);
	printf("\n");

	system("pause");
	return 0;
}

计算一个数的每位之和(递归实现)

写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和
例如,调用DigitSum(1729),则应该返回1+7+2+9,它的和是19
输入:1729,输出:19

#include <stdio.h>
#include <windows.h>

#pragma warning(disable:4996)

int DigitSum(int n){
	if (n > 9){
		return (n % 10) + DigitSum(n / 10);
	}
	else{
		return n;
    }
}


int main(){

	int n = 1729;
	n = DigitSum(n);
	printf("%d\n", n);

	system("pause");
	return 0;
}

递归实现n的k次方

#include <stdio.h>
#include <windows.h>

#pragma warning(disable:4996)

int Power(int n, int k){
	if (k > 0){
		return n*power(n, k - 1);
	}
	else{
		return 1;
	}
}


int main(){

	int n,k;
	printf("请输入n和k# ");
	scanf("%d %d", &n, &k);
	printf("%d\n", power(n, k));

	system("pause");
	return 0;
}

计算斐波那契数

递归和非递归分别实现求第n个斐波那契数

#include <stdio.h>
#include <windows.h>

#pragma warning(disable:4996)

int Fibonacci(int n){
	int num1 = 1;
	int num2 = 1;
	int tmp = 0;
	if ((n == 1) || (n == 2)){
		return 1;
	}
	if (n > 2){
		for (int i = 3; i <= n; i++){
			tmp = num2;
			num2 += num1;
			num1 = tmp;
			tmp = 0;
		}
	}
	return num2;
}

int FibonacciRec(int n){
	int num1 = 1;
	int num2 = 1;
	int tmp = 0;
	if ((n == 1) || (n == 2)){
		return 1;
	}
	if (n > 2){
		return FibonacciRec(n - 1)+FibonacciRec(n - 2);
	}
}


int main(){

	int n;
	printf("请输入n# ");
	scanf("%d", &n);
	printf("%d\n", Fibonacci(n));
	printf("%d\n", FibonacciRec(n));

	system("pause");
	return 0;
}

问题与解决

近期学习到了一些有效的debug技巧,罗列如下:
1、定位bug的最核心思路是“二分查找”。
2、查看中间结果通常有以下两种方法:
  (a)打印日志(printf)(较为麻烦)
  (b)借助调试器(较为方便)
使用VS调试器,必须保证处于Debug模式
Debug是编译生成调试版本的可执行程序。
Release是编译生成发布版本的可执行程序。
调试器的核心操作:
  (1)设置断点
  (2)调试执行

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值