我已经编写了一个功能,当我运行它完美运行时,但是当我使用不同的输入多次运行时会出现问题。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#define MAX_SIZE 20
int SumStr(char *str) {
int i = 0, j = 0, num = 0, tempnum = 0;
char temp[MAX_SIZE];
while (*(str + i) != 0) { //While not NULL - Checked
while (((*(str + i)) >= 48) && ((*(str + i)) <= 57)) { //while str[i] is [0-9]
*(temp + j) = *(str + i);
++j; ++i;
}
if (j != 0) {
tempnum = atoi(temp);
num = tempnum + num;
tempnum = 0;
j = 0;
}
++i;
}
return num;
}
void Test3(char *arr, int sum)
{
int tempSum = SumStr(arr);
if (tempSum != sum)
{
printf("Your Output is %d, Expected: %d (-3)\n", tempSum, sum);
}
}
void main() {
Test3("ax3b5mt11f", 19);
Test3("5$5$5", 15);
Test3("1234", 1234);
Test3("1$0!100", 101);
Test3("1$1!1", 3);
}
该函数的目的是对字符串中的所有数字求和。
当我使用此主程序运行该功能一次时(例如),它可以正常工作;
void main() {
Test3("1$0!100", 101);
}
Output: num=101
但是当main使用不同的输入多次运行该函数时,输出完全错误。
此主要的输出;
void main() {
Test3("ax3b5mt11f", 19);
Test3("5$5$5", 15);
Test3("1234", 1234);
Test3("1$0!100", 101);
Test3("1$1!1", 3);
}
时;
Your Output is 6871, Expected: 15
Your Output is 6718, Expected: 1234
Your Output is 5024, Expected: 101
答案 0 :(得分:5)
一个问题是,在将temp
- 字符串传递给'\0'
之前,您不会终止atoi
字符串。
你可以写:
temp[j] = '\0'; // or: *(temp + j) = '\0';
if (j != 0) { ...
请注意,将未使用'\0'
正确终止的字符序列传递给期望(终止)字符串的函数会产生未定义的行为;这可能是你当时观察到的。
其次,如果输入字符串的最后一个字符是数字,则增加i
两次,从而错过输入的字符串终止字符。这再次导致未定义的行为。要解决此问题,您可以在递增i
之前检查是否位于字符串的末尾:
if (*(str + i) != 0) {
++i;
}
答案 1 :(得分:3)
除了不终止temp[j]
之外,还可以通过在内循环和外循环中递增str
来跳过i
中的终止字符。
当你跳过终止时,它开始处理下一个字符串[或取决于你的编译器/操作系统,任何旧的垃圾]。
btw,while (isdigit(str[i]))
不仅比你的更具可读性,便携性和高效性,而且还不需要注释。
答案 2 :(得分:1)
我想祝贺Lior Gingihashvili使用问题中显示的测试代码。也就是说,IMO是一种很好的工作方式。
此代码不会尝试修复原始代码 - 这已由accepted answer完成。此代码显示了一种完全不同的方法来解决问题。它使用一组不同的库函数 - strcspn()
和strtol()
- 它避免了对源字符串的任何复制(因此它不会遇到null终止字符串的问题)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static
int SumStr(const char *str)
{
int sum = 0;
str += strcspn(str, "0123456789");
while (*str >= '0' && *str <= '9')
{
/*
** Since *str is a digit, the value will not be negative and
** strtol() won't fail unless the value is too big for a long.
** Since we can't include <limits.h> (or <assert.h>, or
** <errno.h>), I plan to ignore overflow.
*/
char *eon;
long val = strtol(str, &eon, 10);
sum += (int)val;
str = eon + strcspn(eon, "0123456789");
}
return sum;
}
static
void Test3(char *arr, int sum)
{
int tempSum = SumStr(arr);
const char *pass_fail = (tempSum == sum) ? "**PASS**" : "!!FAIL!!";
printf("%s Output: %5d, Expected: %5d, Data (%s)\n",
pass_fail, tempSum, sum, arr);
}
int main(void)
{
Test3("ax3b5mt11f", 19);
Test3("5$5$5", 15);
Test3("1234", 1234);
Test3("1$0!100", 101);
Test3("1$1!1", 3);
Test3("x$.!-_+", 0);
Test3("xxx1000y2345z3456=23412!", 30213);
Test3("-0+0-0+0-", 0);
return 0;
}
运行时,代码会生成:
**PASS** Output: 19, Expected: 19, Data (ax3b5mt11f)
**PASS** Output: 15, Expected: 15, Data (5$5$5)
**PASS** Output: 1234, Expected: 1234, Data (1234)
**PASS** Output: 101, Expected: 101, Data (1$0!100)
**PASS** Output: 3, Expected: 3, Data (1$1!1)
**PASS** Output: 0, Expected: 0, Data (x$.!-_+)
**PASS** Output: 30213, Expected: 30213, Data (xxx1000y2345z3456=23412!)
**PASS** Output: 0, Expected: 0, Data (-0+0-0+0-)
(是的:当我在代码中出现错误时,我确实获得了!!FAIL!!
行。)
答案 3 :(得分:0)
正确运行程序:
//Explanations in the commemnts
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#define MAX_SIZE 20
int SumStr(char *str) {
int i = 0, j = 0, num = 0, tempnum = 0;
char temp[MAX_SIZE];
while (*(str + i) != 0) {
//While not NULL - Checked
while ( (( *(str + i)) >= '0') && ((*(str + i)) <= '9') ) // more readable
{ //while str[i] is [0-9]
*(temp + j) = *(str + i);
++j;
++i;
}
if (j != 0) {
*(temp + j) = 0; // termination of the string needed for atoi
tempnum = atoi(temp);
num = tempnum + num;
tempnum = 0;
j = 0;
}
// new:
if (*(str + i) != 0) {
++i;
}
else break; // detection of the end of string
}
return num;
}
void Test3(const char *arr, int sum)
{
int tempSum = SumStr(arr);
if (tempSum != sum)
{
printf("Your Output is %d, Expected: %d (-3)\n", tempSum, sum);
}
}
void main() {
Test3("ax3b5mt11f", 19);
Test3("5$5$5", 15);
Test3("1234", 1234);
Test3("1$0!100", 101);
Test3("1$1!1", 3);
return 0;
}