使用C中的指针时出现分段错误(核心转储)



所以我目前正试图让我的程序读取用户输入(双输入),并使用C中的指针将所述输入存储在堆中。我为堆分配了40个字节,程序运行良好,直到程序提示我输入要存储的输入。在提供第一个输入后,我出现了分段错误。我知道这可能是一个越界错误,或者是一个不适当的取消引用错误,但我不太清楚我是在哪里做的。如有任何帮助,我们将不胜感激。

  • 编辑:很明显,我的问题有点令人困惑,所以需要澄清一下:该程序的目标是获取未指定数量的等级,从初始堆大小40字节开始(项目要求),每当堆满时,就会将其复制到大小为80字节的新堆中,并释放旧的40字节。这种情况一直持续到输入所有成绩为止。

  • 将count作为defAlloc的参数是一个错误,我不太确定为什么我一开始就把它放在那里,但他的已经被删除了。

  • 这方面的分配问题已经解决,现在可以正常工作,我主要遇到了访问堆中元素并更改它们的问题(等级扫描方法)

  • 很抱歉代码混乱或措辞混乱,我对指针的使用和算术以及堆栈溢出的发布都很陌生。感谢您的回复。

  • 输入和输出的示例:输入:81432573.5

输出:在0x8d8010处为堆分配了40个字节在0x8d8010 的堆中存储81

对每个值重复此操作,直到堆满或达到一个sentinel值。

我不想泄露关于输入/输出和项目的一大堆信息,因为这是一项学校作业(出于学术不诚实的目的),但本质上,我的问题出现在gradeScanner方法中,我试图读取输入并将其分配给ptr、ptr+1等。无论是什么原因,都会导致分割错误

void defAllocator(double **grades);
void gradeScanner(int gradeCount, int allocCount, double *grades, double myGrade);
int main() {
int allocCount;
int gradeCount;
double myGrade;
double *grades;
printf("Enter a list of grades below where each grade is seperated by a newline Character");
printf("After the last grade is entered, enter a negative value to end the list");
defAllocator(&grades);
if(grades == NULL) {
printf("null");
}
else
printf("hello");
gradeScanner(gradeCount, allocCount, grades, myGrade);

}

void defAllocator(double **grades) {
double *arr = (double*)malloc(40);
if(arr != NULL) {
printf("Allocated 40 bytes at the heap at %pn", grades);
}
else
printf("failed to allocate array");
*grades = arr;
}

void gradeScanner(int gradeCount, int allocCount, double *grades, double myGrade) {
int i =0;
while(i != 5){
if(scanf("%f", myGrade) > 0 && gradeCount == 0) {
*grades = myGrade;
gradeCount++;
printf("%pn", grades);
printf("%pn", gradeCount);
i++;
}

else if(scanf("%f", myGrade) < 0) {
i = 5;
}
else if(scanf("%f", myGrade) > 0 && gradeCount > 0) {
*(grades + gradeCount) = myGrade;
}

}
}

让我们先获取一些简单的位。等级阵列的分配

你有

void defAllocator();

然后

double myGrade;
double *grades = &myGrade;
defAllocator(grades);

最后是

void defAllocator(double *grades, int count) {
grades = (double*)malloc(40);
printf("Allocated 40 bytes at the heap at %pn", grades);
}

这些线条中几乎没有任何一条是正确的。

  • 函数声明(第一行)与实际函数不匹配
  • 我认为您希望函数以某种方式更新传递给它的"成绩"指针。事先将"等级"设置为指向随机双精度是没有用的。如果你想整洁,只需将其初始化为NULL
  • 然后只使用一个参数调用allocate,即使它应该取2。很明显,你打算通过询问用户并传递来计算出你需要多少,但出于某种原因,你放弃了这个计划
  • allocate函数目前没有检查malloc是否工作
  • allocate函数将丢弃返回的指针。它把它放在成绩争论中,但那是本地的副本
  • 分配器选择40个字节,与它所分配的大小无关

first-分配函数应该是什么样子。我会让它返回指针到分配的内存

double *defAllocator(int count) {
double *arr = (double*)malloc(sizeof(double)*count);
if(arr != NULL)
printf("Allocated 40 bytes at the heap at %pn", arr);
else 
printf("failed to alllocate array");
return arr; 
}

仍然保持硬编码的最大大小。但要将其设为常量,以便您可以在其他地方使用它,例如检查是否输入了太多结果。

所以现在我们得到

const int GRADE_ARRAY_SIZE = 40; 
double *defAllocator(int count);
....
double *gradeArray = defAllocate(GRADE_ARRAY_SIZE);

如果你想,比如说,把指针传进来,并让分配器更新它,那么你需要这个(这是c风格"通过引用传递"的一个例子)

void defAllocator(double **gradeArrayPtr, int count) {
double *arr = (double*)malloc(sizeof(double)*count);
if(arr != NULL)
printf("Allocated 40 bytes at the heap at %pn", arr);
else 
printf("failed to alllocate array");
*gradeArrayPtr = arr;
}

现在做

const int GRADE_ARRAY_SIZE = 40; 
void defAllocator(double **gradeArrayPtr, int count);
....
double *gradeArray = NULL;
defAllocate(&gradeArray, GRADE_ARRAY_SIZE);

其他人指出了扫描程序代码中的错误,但如果分配器不工作,其他任何东西都无法工作

好了,现在分配器已经修复,让我们看看扫描程序代码。我们有

int allocCount;
int gradeCount;
double myGrade;
double *grades;
gradeScanner(gradeCount, allocCount, grades, myGrade);

以及实际功能。

void gradeScanner(int gradeCount, int allocCount, double *grades, double myGrade) {
int i =0;
while(i != 5){
if(scanf("%f", myGrade) > 0 && gradeCount == 0) {
*grades = myGrade;
gradeCount++;
printf("%pn", grades);
printf("%pn", gradeCount);
i++;
}

else if(scanf("%f", myGrade) < 0) {
i = 5;
}
else if(scanf("%f", myGrade) > 0 && gradeCount > 0) {
*(grades + gradeCount) = myGrade;
}

}
}

注意,你的代码调用了多个未定义的行为,所以我猜很难确切地知道发生了什么,但事实上,试图推理UB是一个很大的错误。

让我们看看这件

if(scanf("%f", myGrade) > 0 && gradeCount == 0)
  • gradeCount没有初始化,所以它几乎肯定不是0(UB)
  • scanf返回的是它扫描的东西的数量,而不是它找到的值。因此,如果存在无效输入,则此处为1(%f)或0。我怀疑您看到的是一个值>已输入0。也许不是,但还不清楚
  • 你必须传递一个指向你想要读取的值的指针,你只传递值(myGrade)(UB-很可能在这里死亡)

好的,所以总是错误的(gradeCount!=0),所以我们进入下一个

else if(scanf("%f", myGrade) < 0) {
i = 5;
}
  • 这将从输入中读取下一个值,它不会再次查看同一输入,不清楚这是否是您想要的
  • 在这种情况下,scanf只返回0,1或EOF。也许您正在尝试检测EOF(通常为-1)
  • 您必须传递一个指向要读取的值的指针,您只传递值(myGrade)(UB,非常字符串,很可能再次死亡)

无论如何,由于<0,这只发生在EOF

所以现在我们进入

else if(scanf("%f", myGrade) > 0 && gradeCount > 0) {
*(grades + gradeCount) = myGrade;
}
  • 这会从输入中读取下一个值,你是这个意思吗?

  • "myGrade"而不是"&myGrade'(非常糟糕的UB)

  • 但是scanf可能返回1,并且gradeCount几乎肯定>0(50/50的机会,因为它是统一的)。如果这真的测试为真,我们做

    *(grades + gradeCount) = myGrade;
    

通常情况下,这是写入

grades[gradeCount] = myGrade;

好的gradeCount是未初始化的,所以这是非常糟糕的UB。注意,如果这已经起作用,myGrade也将被统一(也是UB)

所以

  • 初始化所有您的变量
  • 通过引用传入gradeCount,以便更新
  • 阅读scanf上的手册页https://man7.org/linux/man-pages/man3/scanf.3.html

  • 为什么
  • 当输入未通过测试时,你打算继续重读吗

相关内容

  • 没有找到相关文章

最新更新