目录
前言
c语言刚刚刷题时,题目要求对数组进行各种变换,但数组是直接定义好的,不能改(release版本不具有广泛性)。整型数组不知道长度便不知道循环多少次,字符数组对于有空格的输入,scanf忽然“不灵”,现在我关于变长数组,以及关于vs2022不支持c99的替代方案
一.关于变长数组
int n = a+b;
int arr[n];
这样就允许我们自行确定数组的长度了,遗憾的是vs2022不支持,但gcc支持
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);//根据输⼊数值确定数组的⼤⼩
int arr[n];
int i = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
for (i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
二.vs2022不支持变长数组的替代方案
1.非动态内存版
整型数组
不知道循环多少次,就输一个数字,统计一个数字直到回车,这样还不用sizeof函数来求整型数组的长度了。
int arr[1000] = { 0 };
int count = 0;
do
{
scanf("%d", &arr[count]);
count++;
} while (getchar() != '\n');
定义整型数组,[]中不一定要1000,尽可能大就行了,太小了输入容易造成内存溢出。
整型数组中的每一元素用scanf函数不能一次性输完,必须循环输入进去,输完数字,按了一个回车,getchar获取的字符是‘\n'了,自然就停止输入了。
当然也不一定非要用getchar,如果只是达到变长数组的功能,尽管没有以上那么智能。
int arr[100];
int count;
scanf("%d",&count);
for(int i = 0; i < count;i++)
{
scanf("%d",&arr[i])
}
字符数组
对于字符数组,由于可以一口气输完,因此不需要循环。
针对scanf函数“不能”接收空格(输入I am a student失败),下文给出了两种解决方案。
1.scanf
char str[1000] = { 0 };
scanf("%[^\n]", str);
%[]在⽅括号中指定⼀组匹配的字符(⽐如 %[0-9] ),遇到不在集合之中的字符,匹配将会
2.gets
char str[1000] = { 0 };
gets(str);
2.动态内存版
关于动态内存的malloc等函数的讲解,由于篇幅原因,malloc函数太过强大,还可以实现二维数组的任意控制,我会专门开一期来讲。今天先摆结论
malloc实现一维动态数组p[m]
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
int main(void)
{
int m;
scanf("%d", &m);
int* const p = (int*)malloc(m*(sizeof(int)));
memset(p, 0, m);//初始化,每个元素都为零
int i;
//赋值
for (i=0;i<m; i++)
{
p[i] = i;
}
//打印数组
for (i = 0; i <m; i++)
{
printf("%d,", p[i]);
}
return 0;
}
malloc实现二维动态数组p[m][n]:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int main()
{
int m, n;
scanf("%d %d", &m,&n);
int **p;
p = (int**)malloc(m*(sizeof(int*)));//二级指针所在地址申请内存
int i, j;
for (i = 0; i<m; i++)
p[i] = (int*)malloc(sizeof(int)*n);//一级指针所在地址申请内存
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
p[i][j] = i + j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
printf("%d %p ", p[i][j], &p[i][j]); //输出每个元素及地址,每行的列与列之间的地址时连续的,行与行之间的地址不连续
}
printf("\n");
}
return 0;
}
三.补充scanf与gets的讲解
1.scanf函数:
声明
scanf函数是从标准输入 stdin 读取格式化输入的函数,大白话:你想要自己给变量赋值,要用键盘输进去,就用scanf函数。它需要包含的头文件及函数原型是:
#define _CRT_SECURE_NO_WARNINGS 1 //vs环境下需要
#include <stdio.h> //头文件
int scanf(const char *format, ...);//函数原型
参数
具体类型
scanf函数的参数是const char *format,是不是指针,是不是一个地址,所以千万要注意&的使用。你是不是想说你前面字符数组就没加啊。所以关于数组名,大家要记住数组名是是数组首元素的地址,因次,我才敢不加的!!!下面介绍几个容易混淆的输入
char arr[100];
scanf("%s",&arr);//ok,没问题,取数组地址就是数组首元素的地址
scanf("%s",arr);//0k,没问题,数组名就是数组首元素的地址
scanf("%s",&arr[6]);//ok,没问题,就是取数组第7个元素的地址嘛,从第七个元素开始输入
scanf("%s“,arr[6]);//戳啦,arr[6]是一个值,为int类型,我们要的是const*char
总之,就是要关注写的是不是一个指针变量,代表的是一个地址。
具体格式[=%[*][width][modifiers]type=]具体讲解如下:
参数 | 描述 |
* | 这是一个可选的星号,表示数据是从流 stream 中读取的,但是可以被忽视,即它不存储在对应的参数中。 |
width | 这指定了在当前读取操作中读取的最大字符数。 |
modifiers | 为对应的附加参数所指向的数据指定一个不同于整型(针对 d、i 和 n)、无符号整型(针对 o、u 和 x)或浮点型(针对 e、f 和 g)的大小: h :短整型(针对 d、i 和 n),或无符号短整型(针对 o、u 和 x) l :长整型(针对 d、i 和 n),或无符号长整型(针对 o、u 和 x),或双精度型(针对 e、f 和 g) L :长双精度型(针对 e、f 和 g) |
type | 一个字符,指定了要被读取的数据类型以及数据读取方式。具体参见下一个表格。 |
我们先讲常用参数的用法
int year = 0,mouth = 0;
scanf("%d%*c%d", &year, &mouth);
printf("%d.%d", year, mouth);
//输入是2024/2
//输出是2024.2
%*c,其实就相当于,你敲了,但计算机读取完后就丢了,输年月时,别人不空格隔开,就用/,*用*就可以解决他输其它字符的问题。
%后正负号表示对齐方式,数字代表计算机最少打印多少字符,字符不够就用空格。.数字表示最后打印的是几位小数的意思。是向内,自己里面的形式。
现在开始讲type
型 | 合格的输入 | 参数的类型 |
---|---|---|
%a、%A | 读入一个浮点值(仅 C99 有效)。 | float * |
%c | 单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符。 | char * |
%d | 十进制整数:数字前面的 + 或 - 号是可选的。 | int * |
%e、%E、%f、%F、%g、%G | 浮点数:包含了一个小数点、一个可选的前置符号 + 或 -、一个可选的后置字符 e 或 E,以及一个十进制数字。两个有效的实例 -732.103 和 7.12e4 | float * |
%i | 读入十进制,八进制,十六进制整数 。 | int * |
%o | 八进制整数。 | int * |
%s | 字符串。这将读取连续字符,直到遇到一个空格字符(空格字符可以是空白、换行和制表符)。 | char * |
%u | 无符号的十进制整数。 | unsigned int * |
%x、%X | 十六进制整数。 | int * |
%p | 读入一个指针 。 | |
%[] | 扫描字符集合 。 | |
%% | 读 % 符号。 |
%[]前面已讲过,就不再赘述,这里在单独题一嘴的是%g,很智能,如果你要用%f打印,默认保留6位小数,就算限定格式,小数位数变了就要改,不智能,而%g自动缩去没用的0,特别方便!
返回值
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
float f = 0.0f;
int r = scanf("%d %d %f", &a, &b, &f);
printf("a=%d b=%d f=%f\n", a, b, f);
printf("r = %d\n", r);
return 0;
}
2.gets函数
声明
#include <stdio.h>
char *gets(char *str);
相较于scanf,gets就比较简洁了,从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。可以说是专门针对字符串的。
参数
str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
char a[100];
gets(a);
现在再来看,括号里该写什么是不是更有感觉了~
返回值
如果成功,该函数返回 str。如果发生错误或者到达文件末尾时还未读取任何字符,则返回 NULL。
致谢
感谢大家的观看和支持,如有什么错误或不足,欢迎大家留言指正~~