问题描述
顺便说一句,我对编码还很陌生:)
基本上,我正在尝试做一个程序,询问学生他拥有多少年级(<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme">
<receiver android:name="MyReceiver">
<intent-filter>
<action android:name="com.Java_Tutorial.CUSTOM_INTENT"></action>
</intent-filter>
</receiver>
</application>
),并计算出总成绩(nota =等级,葡萄牙语)。 请注意,在每次尝试中,我总是输入'3'和div
的值,并且我只显示部分代码
至于[正确版本],一切对我来说看起来都很正常,并且运行良好。
div
我的疑问与**[CORRECT VERSION]**
short unsigned int div,i;
printf("Pretende fazer a media de quantas notas?(Máximo é 10): ");
scanf("%hd",&div);
float nota[div],media,soma = 0;
for(i = 0; i < div; i++) { //duvida linhas 25-26
pergunta:
printf("A %dª nota foi: ",i+1);
scanf("%f",¬a[i]);
if((nota[i] < 0) || (nota[i] >20)) {
printf("\n(Erro: Por favor insira valores de 0 a 20\n");
goto pergunta;
循环中的[“ NON-SENSE” VERSION]有关。
我了解我在进行循环for
的第一次运行时会假设i++
为 0 ,但是在i
循环中,for
将是 1 。由于array_size = 3,所以三年级(nota)将没有分配插槽(因为nota [0]将被跳过,这使其变为0 ?,仅剩下2个插槽),但是循环仍然运行3次,要求获得3年级并给我整体分数。
i
但是,用**["NON-SENSE VERSION]**
short unsigned int div,soma = 0;
for(i = 0; i++ < div;) { //duvida linhas 25-26
pergunta:
printf("A %dª nota foi: ",i);
scanf("%f",¬a[i]);
if((nota[i] < 0) || (nota[i] >20)) {
printf("\n(Erro: Por favor insira valores de 0 a 20\n");
goto pergunta;
代替div
,即使它与先前版本中假设的3
相同,也遇到了分段错误(以及其他一些总线错误的实验)
div
您能解释一下我所缺少的内容吗,为什么甚至连上一个版本的[“ NON-SENSE” VERSION]也运行?
解决方法
这里有很多要解压的东西,但是让我们按顺序进行吧。
首先,不要这样做:
unsigned div;
scanf("%hd",&div);
float nota[div],media,soma = 0;
如果您知道学生可以输入的最高分数,则应该预先定义MAX_SIZE或使用动态分配。有关更多信息,请参见此StackOverflow question。 您正在做的是创建VLA-可变长度数组。 C99标准中添加了此功能,但由于并非所有编译器都遵守该标准,因此使用它会并且会降低可移植性。
第二,您正在使用非惯用的for循环。编程中的一个习惯用法是事实上做某些事情的标准。我们使用成语是因为它减少了出错的机会,并使其他人更容易阅读和维护我们的代码。这就是为什么我们坚持使用
for(int i = 0,i < n; i++){}
我想您已经意识到了这一点(正如您所说的是无意义的),但是我只是把它发布给任何可能尝试使用看起来像这样for(i = 0; i++ < 3;)
的代码的人-会给您带来讨厌的错误和不想要的行为。
将这两者结合在一起,我们可以看到发生了什么: 在您的废话示例中,您正在使用VLA。其工作方式取决于compiler,但我猜在这种情况下,编译器将查看变量div的类型-由于它是无符号的short,它知道该值在...的范围内。 (0-65,535)*,因此该值相对较小。因为它的值很小,所以它在堆栈上分配了足够的内存来容纳最长约65k的数组。这意味着您可以“安全地”对该内存进行读写,而不会导致堆栈溢出,因为操作系统已授予您的程序写入内存中65k个元素点的权限。
在另一种情况下,您对编译器说数组长度为3个元素,因此程序仅从OS请求3个元素。然后,操作系统不喜欢您尝试从内存中读取和写入内容,而这并没有给您带来好处,因此您最终会收到错误消息。
最后的注释: 请不要使用goto。
*假定无符号短路长度为16b,这是最小值-可以更长,具体取决于系统。