长字符串上的段错误 11,在访问字符串之前,仅当字符串 > 14 时
Segfault 11 on long string, PRIOR to accessing string, only when string > 14
ANSI c OSX 10.13.6
Apple LLVM 版本 9.1.0 (clang-902.0.39.2)
目标:x86_64-apple-darwin17.7.0
线程模型:posix
我在学习c
这是一个手动(逐个字符)相加两个 表示大数字(超过 unsigned long long 或 double 大小)的字符串 的函数。
它适用于任何两个字符串 14 个或更少的字符长,但 segmentation fault 11
任何字符串 大于 14 个字符.
改变字符串的内存分配方式似乎没有效果(即从
char[15] addend1; // not a ptr
到
char *addend1 = (char *) malloc(sizeof(char) * (16) ); // pointer
有一件事很奇怪,它似乎在...上出现段错误
for (int j = maxlength - 1 ; j >= 0; j--)
...在访问 addend1
或 addend2
之前,但我无法在那里找到错误或更改它以防止出现段错误。
是我看错哪里出错了,还是跟for循环有关?
成功运行(少于15个字符)
maxlength = 14
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... DONE
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... DONE
Start adding individual ints from end (right side) ...
13 ...12 ...11 ...10 ...9 ...8 ...7 ...6 ...5 ...4 ...3 ...2 ...1 ...0 ...main.sum = 28147497671064
不成功运行(15 个字符)
maxlength = 15
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... DONE
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... DONE
Start adding individual ints from end (right side) ...
Segmentation fault: 11
MAIN.c
#include <stdio.h>
#include <stdlib.h>
#include "../../c-library/include/addViaStrings.h"
int main(void) {
// s[0] = 72; s[1] = 101; s[2] = 108; s[3] = 108; s[4] = 111; s[5] = 32; s[6] = 87; s[7] = 111; s[8] = 114; s[9] = 108; s[10] = 100; s[11] = 0;
// WORKS
// char s1[] = "14073748835532";
// char s2[] = "14073748835532";
// FAILS
char s1[] = "140737488355328";
char s2[] = "140737488355328";
char *sum = addNumericStrings(&s1, &s2);
printf("main.sum = %s\n", sum);
}
addViaStrings.h
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
char* addNumericStrings(char *s1, char *s2);
char leftPad(char *result, char *s, int maxlength);
int findMaxLength(char *s1, char *s2);
char* addNumericStrings(char *s1, char *s2){
// Find the length of the greater of the two
int maxlength = findMaxLength(s1, s2);
printf("maxlength = %d\n", maxlength); //333
///////////////////////////////////////////////
// Using malloc instead of char[maxlength] seems to have NO EFFECT on the issue
// char addend1[maxlength]; // not a pointer
char *addend1 = (char *) malloc(sizeof(char) * (maxlength + 1) );
addend1[maxlength + 1] = 0; // end flag
// char addend2[maxlength]; // not a pointer
char *addend2 = (char *) malloc(sizeof(char) * (maxlength + 1) );
addend2[maxlength + 1] = 0; // end flag
// Allocate sum pointer
printf("char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... "); //333
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) );
printf("DONE\n"); //333
// General use vars
int a1, a2, total;
int carry = 0;
// Prepare the strings for manual addition. Pad the left with char 0s
leftPad(addend1, s1, maxlength);
leftPad(addend2, s2, maxlength);
// Buffer sum with zeros
sum[maxlength + 1] = 0; // end flag
printf("for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... "); //333
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } // Fill w/ 0s
printf("DONE\n"); //333
// Run the manual addition
// Start adding individual ints from end (right side)
printf("Start adding individual ints from end (right side) ...\n"); //333
// maxlength -1 because(I think) the termination char takes 2 bytes
// If I use (maxlength) instead of (maxlength -1) I get a weird
// question mark char at the end of returnsum
for (int j = maxlength - 1 ; j >= 0; j--) {
///////////////////////////////////////////
// The segfault seems to happen BEFORE accessing addend1 or addend2
printf("%d ...", j); // 333 This DOES NOT print
///////////////////////////////////////////
a1 = addend1[j] - '0'; // Convert to int
a2 = addend2[j] - '0'; // Convert to int
total = (a1 + a2 + carry);
carry = 0;
if ( total >= 10){
carry += 1;
total -= 10;
}
sum[j + 1] = '0'+total; // convert to ascii value for numbers (adding 48)
}
sum[0] = '0' + carry; // add last carry to start of num always, even if 0
// Before returning, truncate leading zeros
char *returnsum = (char *) malloc(sizeof(char) * (strlen(sum) + 1) );
int sum_i = 0;
int returnsm_i = 0;
// bool truncate = true; // Find out why this wont compile
int truncate = 1; // true
while (1){
// if order is important here
if (sum[sum_i] == '[=13=]') { break; } // we're done
if (sum[sum_i] == '0' && truncate == 1) { sum_i += 1; continue; } // 1 is true
// if a num, Stop truncating 0s but DO continue adding numbers
if (sum[sum_i] != '0') { truncate = 0; } // 0 is false
returnsum[returnsm_i] = sum[sum_i];
returnsm_i += 1;
sum_i += 1;
}
return returnsum;
}
char leftPad(char *result, char *s, int maxlength){
int slength = strlen(s);
// buffer with zeros, not '[=13=]'s
for (int i = (maxlength); i >= 0; i--){ result[i] = '0'; }
// right fill result with s
for (int j = 0; j <= slength; j++){
int index = ((maxlength - slength) + j);
result[index] = s[j];
}
result[maxlength + 1] = 0;
}
int findMaxLength(char *s1, char *s2){
// int length1 = findEndLength(s1);
// int length2 = findEndLength(s2);
int length1 = strlen(s1);
int length2 = strlen(s2);
int maxlength;
(length1 > length2) ? (maxlength = length1) : (maxlength = length2);
return maxlength;
}
问题是我试图访问 sum
字符串,好像它比 addends
字符串长一个位置,但我已将其声明为相同长度(即 maxlength + 1
).所以我试图访问实际 sum
数组之后的一个位置。
这是一个有点隐蔽的问题,因为直到sum
的长度需要大于15时,这个访问错误才进入不允许的内存space ,导致段错误。
详情
因为两个加数的总和可能需要数组中至少一个额外的位置,如果总和超过一个(即 999 + 999 = 1998),sum
字符串需要是一个数组位置比加数长。
如果加数为 3 位长(数组长度 = 4),则总和需要为 4 位长(数组长度 = 5)。
// Correct code if "maxlength" (number of actual digits in string) = 14
char *addend1 = (char *) malloc(sizeof(char) * (maxlength + 1) ); // +1 To include termination byte
char *addend2 = (char *) malloc(sizeof(char) * (maxlength + 1) ); // +1 To include termination byte
char *sum = (char *) malloc(sizeof(char) * (maxlength + 2) ); // +2 To include termination byte, AND an extra char at the front
...以便通过 maxlength + 1
访问 sum
的最终实际数字字符
更正代码
注意:因为根据 maxlength
计算数字位数(相对于包括终止符在内的整个数组的长度)令人困惑 - 以及被认为是错误的形式,我已经学会了- 下面的最终代码已被简化以使用更直观的变量。
#include <stdio.h>
#include <stdlib.h>
char* addIntsAsStrings(char *s1, char *s2);
char* addIntsAsStrings(char *s1, char *s2){
// Find the length of the greater of the two
int length1 = strlen(s1);
int length2 = strlen(s2);
int addendDigits;
(length1 > length2) ? (addendDigits = length1) : (addendDigits = length2);
// We need separate strings of so they can be buffered with zeros
// Create the string for the addends and buffer with zeros.
char addend1[addendDigits + 1];
char addend2[addendDigits + 1];
for (int i = 0; i < (addendDigits) ; i++){ // "<" not "<="
addend1[i] = '0'; // buffer w/ 0s
addend2[i] = '0'; // buffer w/ 0s
} // buffer w/ 0s
addend1[addendDigits] = '[=11=]'; // terminate
// put s1 and s2 into buffered addends strings
int s1_index = (strlen(s1) - 1);
int s2_index = (strlen(s2) - 1);
for (int i = (addendDigits - 1); i >= 0; i--){ //Start at back of addend
if ( s1_index >= 0) { addend1[i] = s1[s1_index]; }
if ( s2_index >= 0) { addend2[i] = s2[s2_index]; }
s1_index -= 1;
s2_index -= 1;
}
// Allocate sum pointer. The sum pointer needs to be ONE char
// longer than the addends, in the event that the addends need
// to carry a final one to the front. I.e. 999 + 999 = 1998
int sumDigits = addendDigits + 1;
char *sum = (char *) malloc(sizeof(char) * (sumDigits + 1) ); // +1 To include termination byte, AND an extra char at the front
for (int i = 0; i < (sumDigits) ; i++){ // "<" not "<="
sum[i] = '0'; // buffer w/ 0s
}
sum[sumDigits] = '[=11=]';
// Manual addition vars
int a1, a2, total;
int carry = 0;
// Run the manual addition
// Start adding individual ints from end (right side)
for (int j = addendDigits - 1; j >= 0; j--) {
a1 = addend1[j] - '0'; // Convert to int
a2 = addend2[j] - '0'; // Convert to int
total = (a1 + a2 + carry);
carry = 0;
if ( total >= 10){
carry += 1;
total -= 10;
}
// convert to ascii value for numbers (adding 48)
sum[j + 1] = '0'+total; // sum[j + 1] because `sum`is always one index larger than the addends
}
sum[0] = '0' + carry; // add last carry to start of num always, even if 0
// Before returning, truncate leading zeros
char *returnsum = (char *) malloc(sizeof(char) * (strlen(sum) + 1) );
int sum_i = 0;
int returnsm_i = 0;
int truncate = 1; // true
while (1){
// if order is important here
if (sum[sum_i] == '[=11=]') { break; } // we're done
if (sum[sum_i] == '0' && truncate == 1) { sum_i += 1; continue; } // 1 is true
// if a num, Stop truncating 0s but DO continue adding numbers
if (sum[sum_i] != '0') { truncate = 0; } // 0 is false
returnsum[returnsm_i] = sum[sum_i];
returnsm_i += 1;
sum_i += 1;
}
return returnsum;
}
ANSI c OSX 10.13.6
Apple LLVM 版本 9.1.0 (clang-902.0.39.2)
目标:x86_64-apple-darwin17.7.0
线程模型:posix
我在学习c
这是一个手动(逐个字符)相加两个 表示大数字(超过 unsigned long long 或 double 大小)的字符串 的函数。
它适用于任何两个字符串 14 个或更少的字符长,但 segmentation fault 11
任何字符串 大于 14 个字符.
改变字符串的内存分配方式似乎没有效果(即从char[15] addend1; // not a ptr
到
char *addend1 = (char *) malloc(sizeof(char) * (16) ); // pointer
有一件事很奇怪,它似乎在...上出现段错误
for (int j = maxlength - 1 ; j >= 0; j--)
...在访问 addend1
或 addend2
之前,但我无法在那里找到错误或更改它以防止出现段错误。
是我看错哪里出错了,还是跟for循环有关?
成功运行(少于15个字符)
maxlength = 14
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... DONE
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... DONE
Start adding individual ints from end (right side) ...
13 ...12 ...11 ...10 ...9 ...8 ...7 ...6 ...5 ...4 ...3 ...2 ...1 ...0 ...main.sum = 28147497671064
不成功运行(15 个字符)
maxlength = 15
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... DONE
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... DONE
Start adding individual ints from end (right side) ...
Segmentation fault: 11
MAIN.c
#include <stdio.h>
#include <stdlib.h>
#include "../../c-library/include/addViaStrings.h"
int main(void) {
// s[0] = 72; s[1] = 101; s[2] = 108; s[3] = 108; s[4] = 111; s[5] = 32; s[6] = 87; s[7] = 111; s[8] = 114; s[9] = 108; s[10] = 100; s[11] = 0;
// WORKS
// char s1[] = "14073748835532";
// char s2[] = "14073748835532";
// FAILS
char s1[] = "140737488355328";
char s2[] = "140737488355328";
char *sum = addNumericStrings(&s1, &s2);
printf("main.sum = %s\n", sum);
}
addViaStrings.h
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
char* addNumericStrings(char *s1, char *s2);
char leftPad(char *result, char *s, int maxlength);
int findMaxLength(char *s1, char *s2);
char* addNumericStrings(char *s1, char *s2){
// Find the length of the greater of the two
int maxlength = findMaxLength(s1, s2);
printf("maxlength = %d\n", maxlength); //333
///////////////////////////////////////////////
// Using malloc instead of char[maxlength] seems to have NO EFFECT on the issue
// char addend1[maxlength]; // not a pointer
char *addend1 = (char *) malloc(sizeof(char) * (maxlength + 1) );
addend1[maxlength + 1] = 0; // end flag
// char addend2[maxlength]; // not a pointer
char *addend2 = (char *) malloc(sizeof(char) * (maxlength + 1) );
addend2[maxlength + 1] = 0; // end flag
// Allocate sum pointer
printf("char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... "); //333
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) );
printf("DONE\n"); //333
// General use vars
int a1, a2, total;
int carry = 0;
// Prepare the strings for manual addition. Pad the left with char 0s
leftPad(addend1, s1, maxlength);
leftPad(addend2, s2, maxlength);
// Buffer sum with zeros
sum[maxlength + 1] = 0; // end flag
printf("for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... "); //333
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } // Fill w/ 0s
printf("DONE\n"); //333
// Run the manual addition
// Start adding individual ints from end (right side)
printf("Start adding individual ints from end (right side) ...\n"); //333
// maxlength -1 because(I think) the termination char takes 2 bytes
// If I use (maxlength) instead of (maxlength -1) I get a weird
// question mark char at the end of returnsum
for (int j = maxlength - 1 ; j >= 0; j--) {
///////////////////////////////////////////
// The segfault seems to happen BEFORE accessing addend1 or addend2
printf("%d ...", j); // 333 This DOES NOT print
///////////////////////////////////////////
a1 = addend1[j] - '0'; // Convert to int
a2 = addend2[j] - '0'; // Convert to int
total = (a1 + a2 + carry);
carry = 0;
if ( total >= 10){
carry += 1;
total -= 10;
}
sum[j + 1] = '0'+total; // convert to ascii value for numbers (adding 48)
}
sum[0] = '0' + carry; // add last carry to start of num always, even if 0
// Before returning, truncate leading zeros
char *returnsum = (char *) malloc(sizeof(char) * (strlen(sum) + 1) );
int sum_i = 0;
int returnsm_i = 0;
// bool truncate = true; // Find out why this wont compile
int truncate = 1; // true
while (1){
// if order is important here
if (sum[sum_i] == '[=13=]') { break; } // we're done
if (sum[sum_i] == '0' && truncate == 1) { sum_i += 1; continue; } // 1 is true
// if a num, Stop truncating 0s but DO continue adding numbers
if (sum[sum_i] != '0') { truncate = 0; } // 0 is false
returnsum[returnsm_i] = sum[sum_i];
returnsm_i += 1;
sum_i += 1;
}
return returnsum;
}
char leftPad(char *result, char *s, int maxlength){
int slength = strlen(s);
// buffer with zeros, not '[=13=]'s
for (int i = (maxlength); i >= 0; i--){ result[i] = '0'; }
// right fill result with s
for (int j = 0; j <= slength; j++){
int index = ((maxlength - slength) + j);
result[index] = s[j];
}
result[maxlength + 1] = 0;
}
int findMaxLength(char *s1, char *s2){
// int length1 = findEndLength(s1);
// int length2 = findEndLength(s2);
int length1 = strlen(s1);
int length2 = strlen(s2);
int maxlength;
(length1 > length2) ? (maxlength = length1) : (maxlength = length2);
return maxlength;
}
问题是我试图访问 sum
字符串,好像它比 addends
字符串长一个位置,但我已将其声明为相同长度(即 maxlength + 1
).所以我试图访问实际 sum
数组之后的一个位置。
这是一个有点隐蔽的问题,因为直到sum
的长度需要大于15时,这个访问错误才进入不允许的内存space ,导致段错误。
详情
因为两个加数的总和可能需要数组中至少一个额外的位置,如果总和超过一个(即 999 + 999 = 1998),sum
字符串需要是一个数组位置比加数长。
如果加数为 3 位长(数组长度 = 4),则总和需要为 4 位长(数组长度 = 5)。
// Correct code if "maxlength" (number of actual digits in string) = 14
char *addend1 = (char *) malloc(sizeof(char) * (maxlength + 1) ); // +1 To include termination byte
char *addend2 = (char *) malloc(sizeof(char) * (maxlength + 1) ); // +1 To include termination byte
char *sum = (char *) malloc(sizeof(char) * (maxlength + 2) ); // +2 To include termination byte, AND an extra char at the front
...以便通过 maxlength + 1
sum
的最终实际数字字符
更正代码
注意:因为根据 maxlength
计算数字位数(相对于包括终止符在内的整个数组的长度)令人困惑 - 以及被认为是错误的形式,我已经学会了- 下面的最终代码已被简化以使用更直观的变量。
#include <stdio.h>
#include <stdlib.h>
char* addIntsAsStrings(char *s1, char *s2);
char* addIntsAsStrings(char *s1, char *s2){
// Find the length of the greater of the two
int length1 = strlen(s1);
int length2 = strlen(s2);
int addendDigits;
(length1 > length2) ? (addendDigits = length1) : (addendDigits = length2);
// We need separate strings of so they can be buffered with zeros
// Create the string for the addends and buffer with zeros.
char addend1[addendDigits + 1];
char addend2[addendDigits + 1];
for (int i = 0; i < (addendDigits) ; i++){ // "<" not "<="
addend1[i] = '0'; // buffer w/ 0s
addend2[i] = '0'; // buffer w/ 0s
} // buffer w/ 0s
addend1[addendDigits] = '[=11=]'; // terminate
// put s1 and s2 into buffered addends strings
int s1_index = (strlen(s1) - 1);
int s2_index = (strlen(s2) - 1);
for (int i = (addendDigits - 1); i >= 0; i--){ //Start at back of addend
if ( s1_index >= 0) { addend1[i] = s1[s1_index]; }
if ( s2_index >= 0) { addend2[i] = s2[s2_index]; }
s1_index -= 1;
s2_index -= 1;
}
// Allocate sum pointer. The sum pointer needs to be ONE char
// longer than the addends, in the event that the addends need
// to carry a final one to the front. I.e. 999 + 999 = 1998
int sumDigits = addendDigits + 1;
char *sum = (char *) malloc(sizeof(char) * (sumDigits + 1) ); // +1 To include termination byte, AND an extra char at the front
for (int i = 0; i < (sumDigits) ; i++){ // "<" not "<="
sum[i] = '0'; // buffer w/ 0s
}
sum[sumDigits] = '[=11=]';
// Manual addition vars
int a1, a2, total;
int carry = 0;
// Run the manual addition
// Start adding individual ints from end (right side)
for (int j = addendDigits - 1; j >= 0; j--) {
a1 = addend1[j] - '0'; // Convert to int
a2 = addend2[j] - '0'; // Convert to int
total = (a1 + a2 + carry);
carry = 0;
if ( total >= 10){
carry += 1;
total -= 10;
}
// convert to ascii value for numbers (adding 48)
sum[j + 1] = '0'+total; // sum[j + 1] because `sum`is always one index larger than the addends
}
sum[0] = '0' + carry; // add last carry to start of num always, even if 0
// Before returning, truncate leading zeros
char *returnsum = (char *) malloc(sizeof(char) * (strlen(sum) + 1) );
int sum_i = 0;
int returnsm_i = 0;
int truncate = 1; // true
while (1){
// if order is important here
if (sum[sum_i] == '[=11=]') { break; } // we're done
if (sum[sum_i] == '0' && truncate == 1) { sum_i += 1; continue; } // 1 is true
// if a num, Stop truncating 0s but DO continue adding numbers
if (sum[sum_i] != '0') { truncate = 0; } // 0 is false
returnsum[returnsm_i] = sum[sum_i];
returnsm_i += 1;
sum_i += 1;
}
return returnsum;
}