所以我目前正试图让我的程序读取用户输入(双输入),并使用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
加
- 为什么
- 当输入未通过测试时,你打算继续重读吗