c语言学习笔记

随机数的使用

随机数rand

在使用之前需要引用<stdlib.h>standard library标准库,并且在使用前需要先设置随机数种子。

  • srand(1);设置种子为1
  • int num = rand();调用随机数

需注意C语言中的随机数,并不是随机的,而是根据种子设置的数值进行数学公式计算

公式为int num1=(31*num0+13)%100;

1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <stdlib.h>
int main() {
srand(1);//1设置种子
int num = rand();//2获取随机数
//输出打印
printf("%d\n", num);
return 0;
}

可以看到随机数是根据种子一直固定不变的

这样的随机数并不是我们想要要的,我们需要让他每次计算的数值都并不一样,所以我们需要让种子一直更换,能完成更换的数值就是时间time

1
srand(time(NULL));

在用time之前也需要引用#include <time.h>头文件

1
2
3
4
5
6
7
8
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
srand(time(NULL));
printf("%d",rand());//输出随机数
return 0;
}

这样的结果就会根据时间不停变换值

随机数的范围

但是这样还不是随机数的最终形态,我们需要设定范围。默认的随机数最大范围为

1
#define RAND_MAX 0x7fff

随机数的范围公式为

1
rand()%(m-n+1)+n//m=终数 n=初值

如果我们需要在1~100的范围内获取

1
int num = rand()%100+1;

无论取余的结果是多少最终结果除以100,值就是99,在加上1,就是1~100.

7~23的范围

1
int num = rand()%17+7;

8~49的范围

1
int num = rand() % 42 + 8;

下面就是最终结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
srand(time(NULL));
for (int i = 1; i <= 10; i++)
{
int num1 = rand()%100+1;
//不管随机数是多少,取余一百后范围肯定在0到99之间
//再加1等于范围在1-100之间
int num2 = rand()%17+7;
//对17取余,结果肯定是0到16再统一加上7就是7到23
int num3 = rand() % 42 + 8;
//尾部+1 50-8等于42 再用42加上8范围就是8到49
printf("%d %d %d\n", num1,num2,num3);
}
return 0;
}

vs中使用scanf函数配置

img

1
_CRT_SECURE_NO_WARNINGS

char和int类型的相互转换

点击跳转

跳出循环体

运算符的优先级

break和continue的作用

break和continue都是用来控制循环结构的,主要作用是停止循环。

break和continue的区别

break用于跳出一个循环体或者完全结束一个循环,不仅可以结束其所在的循环,还可结束其外层循环。

注意:

  • 只能在循环体内和switch语句体内使用break。
  • 不管是哪种循环,一旦在循环体中遇到break,系统将完全结束循环,开始执行循环之后的代码。
  • 当break出现在循环体中的switch语句体内时,起作用只是跳出该switch语句体,并不能终止循环体的执行。若想强行终止循环体的执行,可以在循环体中,但并不在switch语句中设置break语句,满足某种条件则跳出本层循环体。

continue语句的作用是跳过本次循环体中剩下尚未执行的语句,立即进行下一次的循环条件判定,可以理解为只是中止(跳过)本次循环,接着开始下一次循环。

注意:

  • continue语句并没有使整个循环终止。
  • continue 只能在循环语句中使用,即只能在 for、while 和 do…while 语句中使用。

goto语句

img

goto a;可以跳到a:

  • a:表示自定义标签
  • goto a表示跳到a:这个位置

指针

有意义的操作:
指针根证书进行加,减操作(每次移动N个步长)
指针跟指针进行减操作(间隔步长)
无意义的操作:
指针跟整数进行乘除操作
指针跟指针进行加、乘、除操作

原因:指针指向不明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//获取0索引的内存地址
int* p1 = &arr[0];

//通过内存地址(指针P)获取数据
printf("%d\n", *p1);
printf("%d\n", (*p1+1));

//获取5索引的内存地址
int* p2 = &arr[5];

//p2 - p1间隔了多少步长
printf("%d\n",p2-p1); //5*4=20
printf("%p\n", p1);
printf("%p\n", p2);

测试数组之间间隔多少步长

十进制(DEC)为20步长

不明指针

1
2
3
4
5
6
7
8
9
//野指针:指向的空间未分配
int a = 10;
int* p1 = &a;
printf("%p\n",p1);
printf("%d\n", *p1);
//p2 野指针
int* p2 = p1 + 10;
printf("%p\n",p2); //P2也能获取到地址以及地址内的数据,但是他可能是其他程序的地址内存
printf("%d\n",p2); //

运行结果

悬空指针

1
2
3
4
5
6
7
8
9
10
11
12
	//悬空指针:指针指向的空间已分配但是被释放了
printf("让程序多执行一步\n");
int* p3=method();
printf("%p\n",p2);
printf("%d\n",*p2);
return 0;
}
int* method() {
int num = 10;
int* p = &num;
return p;
}

运行结果:发现变量不是10了,而是被释放了

void 类型的指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
void swap(void* p1, void* p2, int len);
int main() {
/*
* void 类型的指针
*
没有类型的指针:
特点:无法获取数据,无法计算,但是可以接受任意地址
*/

//定义两个变量
int a = 10;
short b = 20;

//2.定义两个指针
int* p1 = &a;
short* p2 = &b;
printf("%d\n",*p1);
printf("%d\n", *p2);

/*不同类型的指针之间,是不能互相赋值的
void类型的指针打破上面的观念
void没有任何类型,好处是可以接受任意类型指针记录的内存地址*/
void* p3 = p1;
void* p4 = p2;
//缺点:void类型的指针,无法获取变量里面的数据,也不能进行加,减的计算
//printf("%p\n",*p3+1);
int c = 100;
int d = 200;
swap(&c,&d,4);
printf("c=%d,d=%d\n",c,d);
return 0;
}


void swap(void* p1, void* p2, int len) { //8
//把void类型的指针,转成char类型的指针
char* pc1 = (char*)p1;
char* pc2 = (char*)p2;
char temp=0;

//以字节为单位,一个字节一个字节的进行交换
for (int i = 0; i < len; i++)
{
temp = *pc1;
*pc1 = *pc2;
*pc2 = temp;
pc1++;
pc2++;
}
}

运行结果:

10
20
c=200,d=100

可以发现转换成功