目录
[2.1 错误示范](#2.1 错误示范)
[2.1.1 错误的原因](#2.1.1 错误的原因)
4.写一个函数,每调用一次这个函数,就会将num的值增加1。
[7.2 利用递归来正确实现代码](#7.2 利用递归来正确实现代码)
[8.1 利用递归(效率很慢)](#8.1 利用递归(效率很慢))
[8.2 利用循环(不考虑栈溢出,因为这里输入小一点的数正确,大一点就会栈溢出,结果错误,但是效率很快)](#8.2 利用循环(不考虑栈溢出,因为这里输入小一点的数正确,大一点就会栈溢出,结果错误,但是效率很快))
1.利用goto的关机程序
cpp
#define _CRT_SECURE_NO_WARNINGS
//#inculde<string.h> 部分版本需要引用这个头文件
#include<stdio.h>
int main() {
system("shutdown - s - t 60");
char arr[20] = { 0 };
flag:
printf("电脑在1分钟内关机,请输入我是猪来取消关机!");
scanf("%s", arr);
if (strcmp(arr, "我是猪") == 0) {
system("shutdown -a");
}
else {
goto flag;
}
return 0;
}
上述代码简单修改,利用while循环来实现关机.
cpp
#define _CRT_SECURE_NO_WARNINGS
//#inculde<string.h>
#include<stdio.h>
int main() {
system("shutdown - s - t 60");
char arr[20] = { 0 };
while (1) {
printf("电脑在1分钟内关机,请输入我是猪来取消关机!");
scanf("%s", arr);
if (strcmp(arr, "我是猪") == 0) {
system("shutdown -a");
break;
}
}
return 0;
}
!!!! goto语句只能在一个函数范围内跳转,不能跨函数
2.交换两个整数(容易出现的错误)
2.1 错误示范
cpp
#define _CRT_SECURE_NO_WARNINGS
//#inculde<string.h>
#include<stdio.h>
int swap(int x, int y) {
int z = 0;
z = x;
x = y;
y = z;
}
int main() {
int a = 10;
int b = 20;
printf("交换前:a=%d b=%d\n", a, b);
swap(a, b);
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
2.1.1 错误的原因
之所以出现错误是因为函数传参的过程中,a b本身是有地址空间的,但是x y也开辟了地址空间,这就导致他们的地址空间并不一样!
这里相当于给x y开辟了空间,x中放的是10,y中放的是20.然后z也开辟了空间,在执行swap函数中,尽管x y实现了互换,但是根本没有影响a b的值,跟a b都不是一个空间的地址。所以导致了a b的值没有实现互换!
2.1.2 修改正确的版本(利用指针)
举例
cpp
#include<stdio.h>
int main() {
int a = 10;//4个字节的空间
int* pa = &a;//pa就是一个指针变量
*pa = 20;
printf("%d\n", *pa);
printf("%d", a);
return 0;
}
正确版本
cpp
#include<stdio.h>
void swap(int *pa, int *pb) {//void 不用写返回,也可以直接写人return;
int z = *pa;
*pa = *pb;
*pb = z;
}
int main() {
int a = 10;
int b = 20;
printf("交换前:a=%d b=%d\n", a, b);
swap(&a, &b);//传入地址
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
3.函数调用进行折半查找
cpp
#include<stdio.h>
int binary_search(int a[], int k, int s) {
int left = 0;
int right = s - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (a[mid] > k) {
right = mid - 1;
}
else if (a[mid] < k) {
left = mid + 1;
}
else {
return mid;
}
}
return -1;
}
int main(){
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int key = 7;
int sz = sizeof(arr) / sizeof(arr[0]);
int ret = binary_search(arr,key,sz);
if (-1 == ret) {
printf("找不到\n");
}
else {
printf("找到了,下标是:%d\n",ret);
}
return 0;
}
3.1错误版本
cpp
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int binary_search(int a[], int k) {
int sz = sizeof(a) / sizeof(a[0]);//求数组个数,错误
int left = 0;
int right = sz - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (a[mid] > k) {
right = mid - 1;
}
else if (a[mid] < k) {
left = mid + 1;
}
else {
return mid;
}
}
return -1;
}
int main(){
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int key = 7;
int ret = binary_search(arr,key);//不传sz,错误
if (-1 == ret) {
printf("找不到\n");
}
else {
printf("找到了,下标是:%d\n",ret);
}
return 0;
}
3.1.1错误原因
数组arr传参,实际传递的不是数组的本身,仅仅传过去了数组首元素的地址
实际上 int binary_search(int a[], int k)就等于 int binary_search(int *a, int k);int a[ ]就是挂羊头卖狗肉,实际上就是个指针,因此int sz = sizeof(a) / sizeof(a[0]);求得的sz就是4/4=1;再往下进行代码计算就肯定不对了**!**
而在int binary_search(int a[], int k)中int a[ ]中没写大小,如int a[10]是因为数组都没传过来,这里创建一个数组也没意义!
!!!!!所以函数内部需要参数部分传过来数组的个数,一定是在外面求好这个数组个数在传过去,而不是在函数内部在去求!实际上数组传参就是一种传址的效果!
4.写一个函数,每调用一次这个函数,就会将num的值增加1。
cpp
#include<stdio.h>
void Add(int* p) {
(*p)++;
}
int main() {
int num = 0;
Add(&num);
printf("%d\n", num);
Add(&num);
printf("%d\n", num);
Add(&num);
printf("%d\n", num);
return 0;
}
函数内部想改变函数外部,一般都采用传址操作!
4.1使用传值进去
cpp
#include<stdio.h>
int Add(int p) {
p++;
return p;
}
int main() {
int num = 0;
int a=Add(num);
printf("%d\n", a);
int b = Add(num);
printf("%d\n", b);
int c = Add(num);
printf("%d\n", c);
return 0;
}
5.有关print的操作题
cpp
#include<stdio.h>
int main()
{
printf("%d", printf("%d",printf("%d", 43)));
return 0;
}
结果是4321;原因是因为print返回值类型为
函数返回的是打印在屏幕上的字符的个数
所以
6.字符串比较
字符串比较时,1.如
不能直接用 == ,这里需要引入头文件 #incolude<string.h>;然后使用strcmp进行对比;
而如果出现两个字符串比较,如str1="abcd",str2="abce",比较结果为<0,因为字符串比较,实际上比较的是ascii码值,比较的结果有3个为<0,>0,=0.
2.如果定义的是一个数组,那么在scanf中不用加&取地址符。因为对应的password就是数组名,数组名本身就是一个地址了。
3.
这里红色方框比较的是两个字符串的首字符的地址,并没有比较内容。地址比较是没有意义的!
7.编写函数不允许创建临时变量,求字符串的长度。
7.1创建count变量来实现代码
cpp
#include<stdio.h>
int my_strlen(char* str)//*str解引用得到值
{
int count = 0;
while (*str != '\0') {
count++;
str++;//str代表的数组下标,也就是字母的地址
}
return count;
}
int main()
{
char arr[] = "cxs";
//['c']['x']['s']['\0']
//模拟实现一个strlen函数
printf("%d\n",my_strlen(arr));//数组传参,传的是数组的首地址
return 0;
}
7.2 利用递归来正确实现代码
cpp
#include<stdio.h>
int my_strlen(char* str)
{
if(*str != '\0') {
return 1 + my_strlen(str + 1);//也可以是str+1对应的是下一个字母的地址,然后在传给char *atr
}
else {
return 0;
}
}
int main()
{
char arr[] = "cxs";
//['c']['x']['s']['\0']
//模拟实现一个strlen函数
printf("%d\n",my_strlen(arr));//数组传参,传的是数组的首地址
return 0;
}
8.求第n个斐波那契数。(不考虑溢出)
8.1 利用递归(效率很慢)
cs
#include<stdio.h>
int Fib(int n) {
if (n <= 2) {
return 1;
}
else {
return Fib(n - 1) + Fib(n - 2);
}
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
8.2 利用循环(不考虑栈溢出,因为这里输入小一点的数正确,大一点就会栈溢出,结果错误,但是效率很快)
cs
#include<stdio.h>
int Fib(int n) {
int a = 1;
int b = 1;
int c = 1;//c赋值为1;是因为n<2时,直接返回c的值刚好是1!
while (n > 2) {
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
9.数组部分
也会导致求长度不对
cs
#include<stdio.h>
int main(){
int arr[3][4] = { {1,2},{3,4},{5,6} };
int i = 0;
int j = 0;
int a = arr[0][0];
int* p = &arr[0][0];//这里可以看出p是指针,*p解引用是一个值,但是arr想要与指针比较,默认也是指针,需要&解引用
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++) {
printf("%d", *p);
p++;
}
}
printf("\n%d", a);
return 0;
}
9.冒泡排序
cs
#include<stdio.h>
void mao_pao(int a[], int k) {
int i = 0;
int temp;
for (i; i < k - 1; i++) {//会比较9轮
int j = 0;
for (j; j < k - 1 - i; j++) {//每轮会比较的次数
if (a[j] > a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
int main() {
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int len = sizeof(arr) / sizeof(arr[0]);
mao_pao(arr, len);
for (int i = 0; i < len; i++) {
printf("%d", arr[i]);
}
return 0;
}
10.数组名的不同
尽管我们看到三个的地址都一样,但是实际上2和3才是真正意义一样的,因为1虽然代表的是整个数组,但是他的地址也是从第一个元素开始,因此地址才和2 3一样!下面通过例子看看1和2 3 是不一样的!
可以看出,1中的&arr+1,因为是数组地址加1,50-28=28,但是是16进制,就是0x28换算十进制就是40,但是2中的arr+1,是数组首元地址加1,十进制是4。也就是说1中的&arr+1是整个数组地址加1,而2中的arr+1是首元地址+1.