萨西摩尔·槿花 发表于 2023-5-20 20:58:48

DEV C++调试报错Segmentation fault

题目:
Problem Description
搬寝室是很累的,xhd深有体会.时间追述2006年7月9号,那天xhd迫于无奈要从27号楼搬到3号楼,因为10号要封楼了.看着寝室里的n件物品,xhd开始发呆,因为n是一个小于2000的整数,实在是太多了,于是xhd决定随便搬2*k件过去就行了.但还是会很累,因为2*k也不小是一个不大于n的整数.幸运的是xhd根据多年的搬东西的经验发现每搬一次的疲劳度是和左右手的物品的重量差的平方成正比(这里补充一句,xhd每次搬两件东西,左手一件右手一件).例如xhd左手拿重量为3的物品,右手拿重量为6的物品,则他搬完这次的疲劳度为(6-3)^2 = 9.现在可怜的xhd希望知道搬完这2*k件物品后的最佳状态是怎样的(也就是最低的疲劳度),请告诉他吧.
Input
每组输入数据有两行,第一行有两个数n,k(2<=2*k<=n<2000).第二行有n个整数分别表示n件物品的重量(重量是一个小于2^15的正整数).
Output
对应每组输入数据,输出数据只有一个表示他的最少的疲劳度,每个一行.
Sample Input
2 1
1 3
Sample Output
4
代码#include "stdio.h"
#include <stdlib.h>
#include <string.h>
       
//#define LLDmax 9223372036854775805
int compare(const void *a, const void *b)
{
    return *(int*)a - *(int*)b;
}

long long int min(int a,int b)
{
        if(a>b) return b;
        else return a;
}

int main()
{
        int n,k,i,j;
        int arr={0},dp={0};//dp表示在当前物品i,取j对物品时最小疲劳值为 dp
        while(scanf("%d %d",&n,&k))
        {
                for(i=1;i<=n;i++)
                {
                        scanf("%d",&arr);
                }
                arr=0;
                qsort(arr, n, sizeof(int), compare);//升序
                memset(dp, 0, sizeof(dp));
                /*dp=0;
                for(i=0;i<=n;i++)
                {
                        dp=LLDmax;
                }*/
                for(i=2;i<=n;i++)
                {
                        for(j=1;j<=k&&j<=i/2;j++)
                        {
                                dp=min(dp,dp+(arr-arr)*(arr-arr));
                        }
                }
                printf("%d\n",dp);
        }
}



调试错误提示

isdkz 发表于 2023-5-20 20:59:09

Segmentation fault是指程序访问了一个非法的内存地址,导致程序崩溃。在这个代码中,可能会出现数组越界的问题,导致程序访问了不合法的内存地址。建议在代码中加入一些边界检查,确保程序不会访问到不合法的内存地址。

萨西摩尔·槿花 发表于 2023-5-20 20:59:19

"C:\Users\LoganLos\Desktop\QQ截图20230520205820.png"

陶远航 发表于 2023-5-20 21:06:28

在对输入数据的读取时,需要加上判断是否到达文件结尾的语句,否则程序会一直循环下去。可以这样修改:

while (scanf("%d %d", &n, &k) != EOF)// 使用 EOF 判断是否到达文件结尾
{
    for (i = 1; i <= n; i++)
    {
      scanf("%d", &arr);
    }
    arr = 0;
    qsort(arr, n + 1, sizeof(int), compare);
    memset(dp, 0, sizeof(dp));
    for (i = 2; i <= n; i++)
    {
      for (j = 1; j <= k && j <= i / 2; j++)
      {
            dp = min(dp, dp + (arr - arr) * (arr - arr));
      }
    }
    printf("%lld\n", dp);
}
此外,在将 dp 数组赋初值时,最好不要使用 memset 函数,因为这样会将数组中所有元素赋成同一个值,可能会导致问题出现。可以采用手动循环赋值的方式来初始化 dp 数组,例如:


for (i = 0; i <= n; i++)
{
    dp = 0;
}
for (j = 1; j <= k; j++)
{
    dp = dp= (arr - arr) * (arr - arr);
}
这样,就可以避免因使用 memset 导致的问题。

sfqxx 发表于 2023-5-20 21:23:36

您好,我看到您的代码存在两个问题。为了解决这些问题,请尝试以下更改:

1.while 循环的判断条件不够完善

在 C 语言中,scanf() 函数返回输入项的数目。当读到文件结束时,其返回值为EOF, 即-1。但是 while 循环的条件只写了 scanf() 函数的返回值,没有考虑到EOF(或者说程序结束)的情况,所以会没有退出循环。

为了防止这种情况出现,可以通过重写 while 循环的条件来避免。

你可以尝试像下面这样修改代码:


int n, m;
while (scanf("%d%d", &n, &m) == 2) {
    // your code here
}

同时,建议您也在前面添加如下头文件以消除对 EOF 的警告:


#include <stdio.h>
#include <stdlib.h>
2.返回类型与 `%d` 格式化字符不匹配

printf() 函数可以在输出之前对格式进行控制,将输出转换成十六进制、八进制等形式。对于常见的整数类型来说,一般使用"%d"、"%lld" 等等。例如,"%d"代表以十进制形式整型输出。

而在此代码中,为了方便,把 dp 数组设置成整型。


int arr={0},dp={0};
然而,在最后计算的结果输出函数中 ,输出格式却使用了 `%d`,无法正确地打印大于 $2^{31}$ - 1 的数字。所以应该用 `long long int` 类型来定义 min() 返回值的类型,并在 printf() 中使用 %lld 格式。

歌者文明清理员 发表于 2023-5-20 22:10:24

该程序运行时出现段错误,可能是由于数组越界或者内存操作错误导致的。建议使用GDB调试工具进行跟踪和排错,可以通过以下步骤使用GDB调试工具:
编译时添加-g参数生成可调试信息;
启动GDB调试工具:gdb a.out;
在GDB中设置断点:break main;
运行程序:run;
当程序执行到断点时停下来,可以使用各种命令查看变量、打印堆栈信息等。可以使用bt命令查看堆栈信息,使用p命令查看变量的值等;
根据输出结果找到错误并进行修复。
另外,建议在编码过程中添加边界检查、异常处理等代码,可以避免很多错误的发生。

jackz007 发表于 2023-5-21 13:00:36

      这一句
      int arr = {0} , dp = {0}      ;
      数组 dp 开得太大,适当改小一点试试
      int arr = {0} , dp = {0}      ;

zhangjinxuan 发表于 2023-5-21 18:36:36

您的代码是没有问题的,但在大部分普通的电脑上,这段代码可能会报错。

重点在于您声明 arr 以及 dp 数组的行,这一行你申请了大量的内存资源,而不巧的是,这是 main 函数,所以,这些内存空间会申请在栈中。{:10_257:}

更不巧的是,因为您使用的计算机可能是一个普通的电脑,而正常电脑的栈资源只有 1M~2M,所以,arr 和 dp 的数组大小已经远远超过了 2M{:10_266:}

您可以将数组尺寸缩小,但可能会影响代码逻辑,更稳妥的方式是将数组申请在其他的空间中(如全局变量),让我尝试对您的代码进行修改:
#include "stdio.h"
#include <stdlib.h>
#include <string.h>
      
//#define LLDmax 9223372036854775805
int compare(const void *a, const void *b)
{
    return *(int*)a - *(int*)b;
}

long long int min(int a,int b)
{
      if(a>b) return b;
      else return a;
}

int n,k,i,j;
int arr={0},dp={0};//dp表示在当前物品i,取j对物品时最小疲劳值为 dp

int main()
{
      while(scanf("%d %d",&n,&k))
      {
                for(i=1;i<=n;i++)
                {
                        scanf("%d",&arr);
                }
                arr=0;
                qsort(arr, n, sizeof(int), compare);//升序
                memset(dp, 0, sizeof(dp));
                /*dp=0;
                for(i=0;i<=n;i++)
                {
                        dp=LLDmax;
                }*/
                for(i=2;i<=n;i++)
                {
                        for(j=1;j<=k&&j<=i/2;j++)
                        {
                              dp=min(dp,dp+(arr-arr)*(arr-arr));
                        }
                }
                printf("%d\n",dp);
      }
}

全局变量的空间比栈的空间大的多,将一些空间较大的变量一般情况下没有问题。

萨西摩尔·槿花 发表于 2023-5-21 18:54:32

zhangjinxuan 发表于 2023-5-21 18:36
您的代码是没有问题的,但在大部分普通的电脑上,这段代码可能会报错。

重点在于您声明 arr 以及 dp 数 ...

学到了,谢谢(*^▽^*)
页: [1]
查看完整版本: DEV C++调试报错Segmentation fault