【问题标题】:Why does my C code not work everytime?为什么我的 C 代码每次都不能正常工作?
【发布时间】:2018-02-11 23:08:36
【问题描述】:

我编写了这段代码来合并两个排序的数组。所需的输出是:

Merged array:0 1 2 3 4 5 6 7 8 9 10 11 12

我正在使用 gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 来编译我的代码。

问题是有时我在执行 a.out 文件时会得到所需的输出,但在其他情况下,光标会一直闪烁并且没有显示结果。为什么会这样?我的代码有问题吗?

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

int main(void){

//change arrays as per your need but it should be sorted
int a[] = {1,2,3,7,8};
int b[] = {0,3,5,6,9,10,11,12};

int m =sizeof(a) / sizeof(int);
int n =sizeof(b) / sizeof(int);

int index=0, j=0, k=0;
int size = m + n;
int array[size];


while(index < size) {

    while(a[j] < b[k] && j<m ){
        array[index] = a[j];
        ++index;
        ++j;
    }
    while(a[j] > b[k] && k<n){
        array[index] = b[k];
        ++index;
        ++k;            
    }
    while(a[j] == b[k]){
        array[index] = a[j];
        j++; index++;            
    }        
}

printf("Merged array: ");
for(int i=0; i<size; i++)
    printf("%d ", array[i]);

printf("\n");

}

【问题讨论】:

  • haaave 你试过调试吗? ....
  • 我还不知道怎么调试。我不熟悉它。特此指出,我很快就学会了。
  • 对于开发人员来说最重要的工具是调试器,尤其是如果您是初学者。我知道他们不教调试,大多数情况下他们甚至都没有提到它。但是你需要花几个小时来学习如何调试你的程序。 它将为您节省无数小时,让您不必盯着代码问自己为什么它不起作用。
  • 非常感谢 bolov,你说得对,它没有在任何地方提及。我一定会尽快学会调试。

标签: c arrays sorting gcc merge


【解决方案1】:

您有未定义的行为(越界访问数组)。使用gcc -fsanitize=undefined 创建一个可执行文件,可以检测各种不良行为。

% gcc -g fffff.c -Wall -Wextra -fsanitize=undefined
% ./a.out
fffff.c:20:12: runtime error: index 5 out of bounds for type 'int [5]'
fffff.c:20:12: runtime error: load of address 0x7ffd0c0c9804 with insufficient space for an object of type 'int'
0x7ffd0c0c9804: note: pointer points here
  08 00 00 00 04 00 00 00  04 00 00 00 04 00 00 00  00 00 00 00 03 00 00 00  05 00 00 00 06 00 00 00
              ^ 
fffff.c:25:12: runtime error: index 5 out of bounds for type 'int [5]'
fffff.c:25:12: runtime error: load of address 0x7ffd0c0c9804 with insufficient space for an object of type 'int'
0x7ffd0c0c9804: note: pointer points here
  08 00 00 00 04 00 00 00  04 00 00 00 04 00 00 00  00 00 00 00 03 00 00 00  05 00 00 00 06 00 00 00
              ^ 
fffff.c:30:12: runtime T: index 5 out of bounds for type 'int [5]'
fffff.c:30:12: runtime error: load of address 0x7ffd0c0c9804 with insufficient space for an object of type 'int'
0x7ffd0c0c9804: note: pointer points here
  08 00 00 00 04 00 00 00

第 20、25 和 30 行是

20      while(a[j] < b[k] && j<m ){

25      while(a[j] > b[k] && k<n){

30      while(a[j] == b[k]){

【讨论】:

  • 非常感谢。我不熟悉调试。会尽快学会的。
  • @V-ZarD 需要注意的一点是,您可以使用它快速找到问题点,然后您可以使用调试器单步执行代码并检查值
【解决方案2】:

我的代码有问题吗?

是的!

访问a时越界,例如:

while(a[j] < b[k] && j<m ){
    array[index] = a[j];
    ++index;
    ++j;
}

j最终会得到值4,进入if语句的主体,当它试图解析while循环的条件时,会访问a[5],这是越界,从而导致未定义行为(这解释了为什么您的代码有时会运行,而其他代码会挂起)。

您可以通过将 while 循环的条件更改为以下方式来让短路帮助您:

while(j < m && a[j] < b[k]) {

j 达到mm,导致j&lt;m 被评估为假时,将不会通过a[j] &lt; b[k],因为如果至少一个操作数为假,则逻辑与运算将为假。

在您的下一个 while 循环中也会发生同样的情况。所以改成这样:

while(k < n && a[j] > b[k]) {

最后但并非最不重要的是,最后一个 while 循环的条件:

while(a[j] == b[k]){

还将调用未定义行为,因为j 将等于 5,k 等于 8。

改成:

while(j < m && k < n && a[j] == b[k]) {

将阻止调用未定义的行为。

【讨论】:

  • 感谢这个很棒的发现。有什么办法可以在 while(a[j] == b[k]) 中处理这个问题?
  • while(k&lt;n a[j] &gt; b[k]) { 应该是while(k&lt;n &amp;&amp; a[j] &gt; b[k]) {
  • gsamarsa 我做了你指出的改变,但仍然面临同样的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-10
  • 1970-01-01
  • 2016-10-03
  • 1970-01-01
  • 2012-06-10
  • 2013-10-14
相关资源
最近更新 更多