Reputation: 3
The following code compiled fine yesterday for a while, started giving the abort trap: 6
error at one point, then worked fine again for a while, and again started giving the same error. All the answers I've looked up deal with strings of some fixed specified length. I'm not very experienced in programming so any help as to why this is happening is appreciated. (The code is for computing the Zeckendorf representation.)
If I simply use printf
to print the digits one by one instead of using strings the code works fine.
#include <string.h>
// helper function to compute the largest fibonacci number <= n
// this works fine
void maxfib(int n, int *index, int *fib) {
int fib1 = 0;
int fib2 = 1;
int new = fib1 + fib2;
*index = 2;
while (new <= n) {
fib1 = fib2;
fib2 = new;
new = fib1 + fib2;
(*index)++;
if (new == n) {
*fib = new;
}
}
*fib = fib2;
(*index)--;
}
char *zeckendorf(int n) {
int index;
int newindex;
int fib;
char *ans = ""; // I'm guessing the error is coming from here
while (n > 0) {
maxfib(n, &index, &fib);
n -= fib;
maxfib(n, &newindex, &fib);
strcat(ans, "1");
for (int j = index - 1; j > newindex; j--) {
strcat(ans, "0");
}
}
return ans;
}
Upvotes: 0
Views: 480
Reputation: 1787
Basically, you have two approaches when you want to receive a string from function in C
In your case the zeckendorf()
function can determine how much memory is needed for the string. The index of first Fibonacci number less than parameter determines the length of result. Add 1 for terminating zero and you know how much memory you need to allocate.
So, if you choose first approach, you need to pass additional two parameters to zeckendorf()
function: char *buffer
and int size
and write to the buffer instead
of ans
. And you need to have some marker to know if it's first iteration of the while()
loop. If it is, after maxfib(n, &index, &fib);
check the condition index+1<=size
. If condition is true, you can proceed with your function. If not, you can return error immediately.
For second approach initialize the ans
as:
char *ans = NULL;
after maxfib(n, &index, &fib);
add:
if(ans==NULL) {
ans=malloc(index+1);
}
and continue as you did. Return ans
from function. Remember to call free()
in caller, when result is no longer needed to avoid memory leak.
In both cases remember to write the terminating \0
to buffer.
There is also a third approach. You can declare ans as:
static char ans[20];
inside zeckendorf()
. Function shall behave as in first approach, but the buffer and its size is already hardcoded. I recommend to #define BUFSIZE 20
and either declare variable as static char ans[BUFSIZE];
and use BUFSIZE
when checking available size. Please be aware that it works only in single threaded environment. And every call to zeckendorf()
will overwrite the previous result. Consider following code.
char *a,*b;
a=zeckendorf(10);
b=zeckendorf(15);
printf("%s\n",a);
printf("%s\n",b);
The zeckendorf()
function always return the same pointer. So a
and b
would pointer to the same buffer, where the string for 15
would be stored. So, you either need to store the result somewhere, or do processing in proper order:
a=zeckendorf(10);
printf("%s\n",a);
b=zeckendorf(15);
printf("%s\n",b);
As a rule of thumb majority (if not all) Linux standard C library function uses either first or third approach.
Upvotes: 1
Reputation: 409196
Your guess is quite correct:
char *ans = ""; // I'm guessing the error is coming from here
That makes ans
point to a read-only array of one character, whose only element is the string terminator. Trying to append to this will write out of bounds and give you undefined behavior.
One solution is to dynamically allocate memory for the string, and if you don't know the size beforehand then you need to reallocate to increase the size. If you do this, don't forget to add space for the string terminator, and to free the memory once you're done with it.
Upvotes: 4