C语言实现getIntPositive正整数校验时nullptr错误排查
问题描述
练习函数与指针相关编程时,耗时超过12小时调试代码仍未解决nullptr相关报错,检索公开的nullptr问题解决方案均未修复问题。
本次任务要求实现int getIntPositive(int *xPtr)函数,功能如下:
- 读取用户输入的数值(任务默认测试输入为-1、0、24)
- 校验输入是否为非零正整数
- 校验通过的数值返回的同时,赋值给指针形参指向的内存空间
- 最终将值传递给预置的
int testIntFunction(void)测试函数
题目要求main.c中的主函数、测试函数及其余预置代码均不可修改,仅可编写getIntPositive函数的实现逻辑,以下代码已删除main.c中与该问题无关的其余内容。
当前需要全部通过3项内置测试,但代码存在两类互斥异常: - 第一类:仅能通过Test1,执行Test2时触发nullptr错误
- 第二类:调整代码顺序后可通过Test2,但Test1、Test3失败,失败原因为要求intA与intB值相等,但实际运行时intA为0、intB为24,二者不相等
相关代码
// --------------------------------------- // Macros and headers // --------------------------------------- #define MAX_PROD 3 #define TEST_NEG -1 #define TEST_ZERO 0 #define TEST_INT 24 #define TEST_DBL 82.5 #include <stdio.h> // --------------------------------------- // Function prototypes // --------------------------------------- int testIntFunction(void); int getIntPositive(int *xPtr); // --------------------------------------- // Main entry-point to the program (main.c) Must not modify, fixed // --------------------------------------- int main(void) { int preTestFailed = 0; printf("============================\n"); printf("Pre-testing Helper Functions\n"); printf("============================\n\n"); preTestFailed += testIntFunction(); if (preTestFailed) { printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"); printf(" Pretesting revealed ERRORS in the helper functions.\n"); printf(" Review where the tests failed and fix these errors\n"); printf(" before continuing.\n"); printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n"); } else { printf("===========================\n"); printf("Starting Main Program Logic\n"); printf("===========================\n\n"); // Entry-point to program logic start(); } return 0; } // --------------------------------------- // My own function (placed in another .c file) The only part can be modified. // --------------------------------------- // 1. Get user input of int type and validate for a positive non-zero number // (return the number while also assigning it to the pointer argument) int getIntPositive(int *xPtr) { int x; int flag = 0; do { scanf("%d", &x); if (x <= 0) { printf("ERROR: Enter a positive value: "); flag = 1; } else { flag = 0; *xPtr = x; xPtr = &x; } } while (flag != 0); return *xPtr; } // --------------------------------------- // Preset functions ( Must not modify, fixed) // --------------------------------------- int testIntFunction(void) { int intA = 0, intB = 0, fail=0; printf("------------------------\n"); printf("Function: getIntPositive\n"); printf("------------------------\n"); printf("For each of these tests, enter the following\n"); printf("three values (space delimited): %d %d %d\n\n", TEST_NEG, TEST_ZERO, TEST_INT); //----------------------------------- // Test-1: argument and return value printf("TEST-1: "); intB = getIntPositive(&intA); if (intA == intB && intA == TEST_INT) { printf("<PASSED>\n"); } else { printf("<!!! FAILED !!!>\n"); fail++; } //----------------------------------- // Test-2: return value only intA = intB = 0; printf("TEST-2: "); intA = getIntPositive(NULL); if (intA == TEST_INT) { printf("<PASSED>\n"); } else { printf("<!!! FAILED !!!>\n"); fail++; } //----------------------------------- // Test-3: argument only intA = intB = 0; printf("TEST-3: "); getIntPositive(&intA); if (intA == TEST_INT) { printf("<PASSED>\n\n"); } else { printf("<!!! FAILED !!!>\n"); fail++; } return fail; } void start() {}
异常表现
第一版代码异常
第一版代码运行时,执行到Test2程序因nullptr错误终止,调试查看局部变量可见x=24,xPtr=0x00000000空指针,运行输出如下:
============================ Pre-testing Helper Functions ============================ ------------------------ Function: getIntPositive ------------------------ For each of these tests, enter the following three values (space delimited): -1 0 24 TEST-1: -1 0 24 ERROR: Enter a positive value: ERROR: Enter a positive value: <PASSED> TEST-2: -1 0 24 ERROR: Enter a positive value: ERROR: Enter a positive value:
调整代码顺序后的异常
将else分支内代码顺序调整为先执行xPtr = &x、再执行*xPtr = x,nullptr错误消失,但Test1、Test3运行失败,调试可见intA=0、intB=24,不符合预期,运行输出如下:
============================ Pre-testing Helper Functions ============================ ------------------------ Function: getIntPositive ------------------------ For each of these tests, enter the following three values (space delimited): -1 0 24 TEST-1: -1 0 24 ERROR: Enter a positive value: ERROR: Enter a positive value: <!!! FAILED !!!> TEST-2: -1 0 24 ERROR: Enter a positive value: ERROR: Enter a positive value: <PASSED> TEST-3: -1 0 24 ERROR: Enter a positive value: ERROR: Enter a positive value: <!!! FAILED !!!>
错误原因
代码存在两个核心逻辑错误:
- 未做空指针校验:Test2直接传入NULL作为参数,原代码不判断指针是否有效直接解引用执行
*xPtr = x,必然触发空指针访问崩溃。 - 错误修改形参指针的指向:原代码在else分支中执行
xPtr = &x,把形参指针指向了函数内的局部变量x,当外部传入有效地址(比如&intA)时,赋值操作只会修改局部变量x,不会写入外部传入的地址对应的内存,导致Test1、Test3中的intA始终是初始值0,校验失败。
修复方案
修改getIntPositive函数逻辑,增加空指针判断,不修改形参指针的指向,直接返回校验通过的局部变量值即可,正确实现如下:
int getIntPositive(int *xPtr) { int x; int flag = 0; do { scanf("%d", &x); if (x <= 0) { printf("ERROR: Enter a positive value: "); flag = 1; } else { flag = 0; // 仅当传入指针非空时,才给指针指向的内存空间赋值 if (xPtr != NULL) { *xPtr = x; } } } while (flag != 0); // 直接返回校验通过的输入值,无需解引用指针 return x; }
修复后三个测试场景全部适配:
- Test1:传入&intA,指针有效,intA被赋值为24,返回值24赋值给intB,二者相等,校验通过
- Test2:传入NULL,跳过指针赋值逻辑,直接返回24,intA接收到返回值24,校验通过
- Test3:传入&intA,指针有效,intA被赋值为24,无需使用返回值,校验通过
内容的提问来源于stack exchange,提问作者Alpaca Ma
相关产品推荐
相关产品推荐

