Caesar Cipher Program - Absurd Number in Array Output - c

I'm actually writing about the same program as before, but I feel like I've made significant progress since the last time. I have a new question however; I have a function designed to store the frequencies of letters contained within the message inside an array so I can do some comparison checks later. When I ran a test segment through the function by outputting all of my array entries to see what their values are, it seems to be storing some absurd numbers. Here's the function of issue:
void calcFreq ( float found[] )
{
char infname[15], alpha[27];
char ch;
float count = 0;
FILE *fin;
int i = 0;
while (i < 26) {
alpha[i] = 'A' + i++;
}
printf("Please input the name of the file you wish to scan:\n");
scanf("%s", infname);
fin = fopen ( infname, "r");
while ( !feof(fin) ) {
fscanf(fin, "%c", &ch);
if ( isalpha(ch) ) {
count += 1;
i = 0;
if ( islower(ch) ) { ch = toupper(ch); }
while ( i < 26 ) {
if ( ch == alpha[i] ) {
found[i]++;
i = 30;
}
i++;
}
}
}
fclose(fin);
i = 0;
while ( i < 26 ) {
found[i] = found[i] / count;
printf("%f\n", found[i]);
i++;
}
}
At like... found[5], I get this hugely absurd number stored in there. Is there anything you can see that I'm just overlooking? Also, some array values are 0 and I'm pretty certain that every character of the alphabet is being used at least once in the text files I'm using.
I feel like a moron - this program should be easy, but I keep overlooking simple mistakes that cost me a lot of time >.> Thank you so much for your help.
EDIT So... I set the entries to 0 of the frequency array and it seems to turn out okay - in a Linux environment. When I try to use an IDE from a Windows environment, the program does nothing and Windows crashes. What the heck?

Here are a few pointers besides the most important one of initializing found[], which was mentioned in other comments.
the alpha[] array complicates things, and you don't need it. See below for a modified file-read-loop that doesn't need the alpha[] array to count the letters in the file.
And strictly speaking, the expression you're using to initialize the alpha[] array:
alpha[i] = 'A' + i++;
has undefined behavior because you modify i as well as use it as an index in two different parts of the expression. The good news is that since you don't need alpha[] you can get rid of its initialization entirely.
The way you're checking for EOF is incorrect - it'll result in you acting on the last character in the file twice (since the fscanf() call that results in an EOF will not change the value of ch). feof() won't return true until after the read that occurs at the end of the file. Change your ch variable to an int type, and modify the loop that reads the file to something like:
// assumes that `ch` is declared as `int`
while ( (ch = fgetc(fin)) != EOF ) {
if ( isalpha(ch) ) {
count += 1;
ch = toupper(ch);
// the following line is technically non-portable,
// but works for ASCII targets.
// I assume this will work for you because the way you
// initialized the `alpha[]` array assumed that `A`..`Z`
// were consecutive.
int index = ch - 'A';
found[index] += 1;
}
}

alpha[i] = 'A' + i++;
This is undefined behavior in C. Anything can happen when you do this, including crashes. Read this link.
Generally I would advise you to replace your while loops with for loops, when the maximum number of iterations is already known. This makes the code easier to read and possibly faster as well.
Is there a reason you are using float for counter variables? That doesn't make sense.
'i = 30;' What is this supposed to mean? If your intention was to end the loop, use a break statement instead of some mysterious magic number. If your intention was something else, then your code isn't doing what you think it does.
You should include some error handling if the file was not found. fin = fopen(..) and then if(fin == NULL) handle errors. I would say this is the most likely cause of the crash.

Check the definition of found[] in the caller function. You're probably running out of bounds.

Related

Count Different Character Types In String

I wrote a program that counts and prints the number of occurrences of elements in a string but it throws a garbage value when i use fgets() but for gets() it's not so.
Here is my code:
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
int main() {
char c[1005];
fgets(c, 1005, stdin);
int cnt[26] = {0};
for (int i = 0; i < strlen(c); i++) {
cnt[c[i] - 'a']++;
}
for (int i = 0; i < strlen(c); i++) {
if(cnt[c[i]-'a'] != 0) {
printf("%c %d\n", c[i], cnt[c[i] - 'a']);
cnt[c[i] - 'a'] = 0;
}
}
return 0;
}
This is what I get when I use fgets():
baaaabca
b 2
a 5
c 1
32767
--------------------------------
Process exited after 8.61 seconds with return value 0
Press any key to continue . . . _
I fixed it by using gets and got the correct result but i still don't understand why fgets() gives wrong result
Hurray! So, the most important reason your code is failing is that your code does not observe the following inviolable advice:
Always sanitize your inputs
What this means is that if you let the user input anything then he/she/it can break your code. This is a major, common source of problems in all areas of computer science. It is so well known that a NASA engineer has given us the tale of Little Bobby Tables:
Exploits of a Mom #xkcd.com
It is always worth reading the explanation even if you get it already #explainxkcd.com
medium.com wrote an article about “How Little Bobby Tables Ruined the Internet”
Heck, Bobby’s even got his own website — bobby-tables.com
Okay, so, all that stuff is about SQL injection, but the point is, validate your input before blithely using it. There are many, many examples of C programs that fail because they do not carefully manage input. One of the most recent and widely known is the Heartbleed Bug.
For more fun side reading, here is a superlatively-titled list of “The 10 Worst Programming Mistakes In History” #makeuseof.com — a good number of which were caused by failure to process bad input!
Academia, methinks, often fails students by not having an entire course on just input processing. Instead we tend to pretend that the issue will be later understood and handled — code in academia, science, online competition forums, etc, often assumes valid input!
Where your code went wrong
Using gets() is dangerous because it does not stop reading and storing input as long as the user is supplying it. It has created so many software vulnerabilities that the C Standard has (at long last) officially removed it from C. SO actually has an excellent post on it: Why is the gets function so dangerous that it should not be used?
But it does remove the Enter key from the end of the user’s input!
fgets(), in contrast, stops reading input at some point! However, it also lets you know whether you actually got an entire line of of text by not removing that Enter key.
Hence, assuming the user types: b a n a n a Enter
gets() returns the string "banana"
fgets() returns the string "banana\n"
That newline character '\n' (what you get when the user presses the Enter key) messes up your code because your code only accepts (or works correctly given) minuscule alphabet letters!
The Fix
The fix is to reject anything that your algorithm does not like. The easiest way to recognize “good” input is to have a list of it:
// Here is a complete list of VALID INPUTS that we can histogram
//
const char letters[] = "abcdefghijklmnopqrstuvwxyz";
Now we want to create a mapping from each letter in letters[] to an array of integers (its name doesn’t matter, but we’re calling it count[]). Let’s wrap that up in a little function:
// Here is our mapping of letters[] ←→ integers[]
// • supply a valid input → get an integer unique to that specific input
// • supply an invalid input → get an integer shared with ALL invalid input
//
int * histogram(char c) {
static int fooey; // number of invalid inputs
static int count[sizeof(letters)] = {0}; // numbers of each valid input 'a'..'z'
const char * p = strchr(letters, c); // find the valid input, else NULL
if (p) {
int index = p - letters; // 'a'=0, 'b'=1, ... (same order as in letters[])
return &count[index]; // VALID INPUT → the corresponding integer in count[]
}
else return &fooey; // INVALID INPUT → returns a dummy integer
}
For the more astute among you, this is rather verbose: we can totally get rid of those fooey and index variables.
“Okay, okay, that’s some pretty fancy stuff there, mister. I’m a bloomin’ beginner. What about me, huh?”
Easy. Just check that your character is in range:
int * histogram(char c) {
static int fooey = 0;
static int count[26] = {0};
if (('a' <= c) && (c <= 'z')) return &count[c - 'a'];
return &fooey;
}
“But EBCDIC...!”
Fine. The following will work with both EBCDIC and ASCII:
int * histogram(char c) {
static int fooey = 0;
static int count[26] = {0};
if (('a' <= c) && (c <= 'i')) return &count[ 0 + c - 'a'];
if (('j' <= c) && (c <= 'r')) return &count[ 9 + c - 'j'];
if (('s' <= c) && (c <= 'z')) return &count[18 + c - 's'];
return &fooey;
}
You will honestly never have to worry about any other character encoding for the Latin minuscules 'a'..'z'.Prove me wrong.
Back to main()
Before we forget, stick the required magic at the top of your program:
#include <stdio.h>
#include <string.h>
Now we can put our fancy-pants histogram mapping to use, without the possibility of undefined behavior due to bad input.
int main() {
// Ask for and get user input
char s[1005];
printf("s? ");
fgets(s, 1005, stdin);
// Histogram the input
for (int i = 0; i < strlen(s); i++) {
*histogram(s[i]) += 1;
}
// Print out the histogram, not printing zeros
for (int i = 0; i < strlen(letters); i++) {
if (*histogram(letters[i])) {
printf("%c %d\n", letters[i], *histogram(letters[i]));
}
}
return 0;
}
We make sure to read and store no more than 1004 characters (plus the terminating nul), and we prevent unwanted input from indexing outside of our histogram’s count[] array! Win-win!
s? a - ba na na !
a 4
b 1
n 2
But wait, there’s more!
We can totally reuse our histogram. Check out this little function:
// Reset the histogram to all zeros
//
void clear_histogram(void) {
for (const char * p = letters; *p; p++)
*histogram(*p) = 0;
}
All this stuff is not obvious. User input is hard. But you will find that it doesn’t have to be impossibly difficult genius-level stuff. It should be entertaining!
Other ways you could handle input is to transform things into acceptable values. For example you can use tolower() to convert any majuscule letters to your histogram’s input set.
s? ba na NA!
a 3
b 1
n 2
But I digress again...
Hang in there!

Is there a better way of modifying arrays from within a function in C?

I am trying to create a formatted string , however I do not know why I cannot print global array which I have modified inside the function.Also the strange behavior is that I cannot access only a specific global array (rand_session_key) rest of the other global arrays are behaving as normal(similar operations are being done on them except their size varies) and I can access their value properly. This code is run on an esp32 (DOIT Dev Kit V1) (with Arduino-Core) , when I run this program on my computer (modifying a few functions etc.) the result is what I expect , I think I am overlapping the characters in the memory or accessing it the wrong way , but had it been the case I would not have yielded the expected output on my computer.
I tried to modify my program and made it more verbose. Also I ran the same code (with some obvious modifications to make it run on my computer) , and the result is good as expected.
char persistent_peripheral_id[] = "FRUCTOSE96";
char rand_session_iden[7] = {'\0'};
char rand_session_key[17] = {'\0'};
char rand_session_channel[3] = {'\0'};
char *generate_random_session_identifier(char *rand_session_iden_local)
{
srand(time(NULL));
int counter = 0;
for (counter = 0; counter < 6; counter++)
*(rand_session_iden_local + counter) = (random(10) % ('~' - ' ')) + 'k';
rand_session_iden_local[counter] = '\0';
printf("Identifier : %s\n", rand_session_iden); //acessing global defintion of array everything is good until here
return &rand_session_iden_local[0];
}
char *generate_random_session_key(char *rand_session_key_local)
{
srand(time(NULL));
int counter = 0;
for (counter = 0; counter < 16; counter++)
*(rand_session_key_local + counter) = (random(10) % ('~' - ' ')) + 'b';
rand_session_key_local[counter] = '\0';
printf("Key : %s\n", rand_session_key);//acessing global defintion of array everything is good until here
return &rand_session_key_local[0];
}
char *generate_random_session_channel(char *rand_session_channel_local)
{
srand(time(NULL));
int channel_value = random(100);
sprintf(rand_session_channel_local, "%03ld", channel_value);
printf("Channel : %s\n", rand_session_channel);//acessing global defintion of array everything is good until here
return &rand_session_channel_local[0];
}
void begin_exchange_package()
{
//If this does not works here (observe rand_session_key) , it will not work for sprintf also ??
printf("\n %s-%s-%s-%s \n", (char *)persistent_peripheral_id,
generate_random_session_identifier(rand_session_iden),
generate_random_session_key(rand_session_key),
generate_random_session_channel(rand_session_channel));
//Notice it prints here ????
printf("\n %s \n",generate_random_session_key(rand_session_key));
Serial.println("Done");
//sprintf((char *)plain_text_package, "{\"p\":\"%s\",\"r\":\"%s\",\"k\":\"%s\",\"c\":\"%s\"}", (char *)persistent_peripheral_id,(char *)rand_session_iden, (char *)rand_session_key , (char *)rand_session_channel);
}
void setup()
{
Serial.begin(115200);
begin_exchange_package();
}
void loop()
{
}
The Output is
FRUCTOSE96-tnltkp--094
Where I expected all the 4 arrays to be printed ?? but it does print separately , is my array being terminated in the wrong way ?? also the logic to assign a random character will always yield a printable ASCII Character (I learned this from a forum on esp32's website)
This code ...
sprintf(rand_session_channel_local, "%03ld", channel_value);
... requires rand_session_channel_local to point to an array of at least four characters, because at will print at least three digits plus a string terminator. The array into which it points, rand_session_channel, is only three characters long. The resulting behavior is undefined.
The observed manifestation of the UB is consistent with the global arrays being laid out in memory such that rand_session_key immediately follows rand_session_channel, such that overflowing the latter means that the string terminator is written to position 0 of the former, making it an empty string. Note, however, that you cannot rely on predicting manifestations of UB, nor is it generally of much use to analyze them. Instead, avoid exercising UB.
It's unclear what random function you are using, since the C standard library's does not take an argument, but if the argument to yours specifies an exclusive upper bound then you could just change the sprintf format to "%02ld". Alternatively, increase the size of rand_session_channel to at least 4.

Structure variable in an if statement

I need to make an C application for school and im stuck at one bit. I filled my struct with word from a file wich works fine, except for the time it just prints a random integer i guess?
My code:
char buffer[20];
int i;
for(i = 0; i < 10; i++) {
fgets(buffer,20,fp);
apcWordList[i].pcWord = strdup(buffer);
apcWordList[i].cMaxScore = 0;
apcWordList[i].tTime = time(NULL);
}
fclose(fp);
Now what i wanted to do was this(sSecretWord is the word the person guessed and score the points he got for guessing the word):
for(i = 0; i < 10; i++) {
fgets(buffer,20,fp);
if(apcWordList[i].pcWord == sSecretWord && score > apcWordList[i].cMaxScore) {
apcWordList[i].cMaxScore = score;
apcWordList[i].tTime = time(NULL);
}
}
but it crashes and I am really confused how to compare the variables and change them when needed. I hope I have explained it well enough and my English could be read well.
Assuming pcWord is a char *, you cannot compare that pointer using ==, most of the time.
There is no string data type in C, a string is never a single value.
You must use strcmp():
if(strcmp(apcWordList[i].pcWord, sSecretWorD) == 0 &&
score > apcWordList[i].cMaxScore)
The rest of your code makes little sense, I'm afraid. The loop has a typo, and there's no connection between the fgets() and the if. I don't think the fgets() should be in the second part of the code, at all.
The following expression in your if condition
apcWordList[i].pcWord == sSecretWord
compares the memory addresses they evaluate to and not the values stored at those memory locations which is probably what you want. You should use strcmp instead to compare the strings pointed to by above two variables.
strcmp(apcWordList[i].pcWord, sSecretWorD) == 0

Segmentation fault when indexing into char array via pointer

My code is causing a segmentation fault when accessing an array element even though that element was already accessed without a problem.
int charToInt(char a)
{
int b;
if(isdigit(a))
{
b = a - '0' - 1;
}
if(isalpha(a))
{
b = a - 65;
}
return b;
}
int validPosition(char **array, int r, int c, char* position, int slots)
{
int i,k;
if(strlen(position) == 5)
{
if(!isalpha(position[0]) || !isdigit(position[1]) || position[2]!=' ' || (position[3]!='N' && position[3]!='E' && position[3]!='W' && position[3]!='S')) //lathos gramma
{
printf("\n%s", "Invalid answear.This is an example of a valid answear: A5 N");
return 2;
}
if( charToInt(position[0]) > r - 1 || charToInt(position[1]) > c - 1 )//ama vgainei eksw apo ta oria
{
printf("\n%s", "The position you choosed is out of the bountries...");
return 2;
}
printf("\n%s%c%s","position[3] is: ",position[3], " but it doesn't work >_<"); // position[3] is N
if(position[3] == 'N') //the problem is here <~~~~~~~~~~~~~~~~~~~<
{
printf("\n%s", "come on");
if(charToInt(position[0]) + slots < r)
{
for(i=charToInt(position[0])-1; i<charToInt(position[0])+slots; i++)
{
if(array[i-1][charToInt(position[1])-1] != '.')
{
printf("\n%s", "The position you choosed is not valid because there is oneother ship there");
return 2;
}
}
}
else
{
printf("\n%s", "The ship is going out of the bountries...");
return 2;
}
}
}
}
When position holds the string "A9 N", the printf correctly outputs 'N' for position[3]. For some reason when it tries to do if(position[3] == 'N'), however, a segmentation fault occurs.
Example program run:
Example of positioning: G3 E
Aircraft carrier (5 places), Give location and direction: A9 N
1
position[3] is: N but it doesn't work >_<
Well, based on your updates, it seems you have a variety of problems. For future reference, actually adding in the (possibly simplified) code showing how you were calling the function in question is better than trying to describe it using prose in a comment. There will be less guesswork for the people trying to help you.
If I'm reading your comment correctly, the code that calls validPosition looks something like this:
// "r and c are 9 and 9 in the specific example(rows columns)."
int rows = 9;
int columns = 9;
// "slots=5."
int slots = 5;
// "array is a 2d array and it contains characters(created with malloc)."
char **array = malloc(rows * columns * sizeof(char));
// "i created char position[10] in the function that called this function"
char position[10];
// "and with fgets(position, 10, stdin); i putted A9 N inside it."
fgets(position, 10, stdin);
validPosition(array, rows, columns, position, slots);
The first problem is your description of the allocation of array (I apologize if I misunderstood your comment and this isn't actually what you are doing). It should look similar to the code below for a dynamically sized two-dimensional array used with two subscripting operations (array[index1][index2], as it is in validPosition). Pointers-to-pointers (char **array) act differently than fixed sized multi-dimensional arrays (array[SIZE1][SIZE2]) when you access them that way.
// each entry in array should be a pointer to an array of char
char **array = malloc(rows * sizeof(char*));
for(i = 0; i < rows; i++)
array[i] = malloc(columns * sizeof(char));
You also need to be careful about using position after the fgets call. You should check the return value to make sure it isn't NULL (indicating an EOF or error condition). The string may not be \0-terminated in this case. In fact, all the elements may still be uninitialized (assuming you didn't initialized them before the call). This can lead to undefined behavior.
The next issue is that validPosition does not return a value on every code path. One example is if strlen(position) != 5. The other is if you enter the for loop and array[i-1][charToInt(position[1])-1] != '.' is never true (that is, the ship placement is deemed valid).
As strange as it is for an English speaker to say this to a Greek author, lets ignore internationalization and focus only on the default C local. The checks on position[0] should therefore be sufficient, though you might consider allowing your users to use lowercase letters as well. When converting position[1] from 1-based to 0-based, however, you do not account for the case when it is '0', which will result in charToInt returning -1. Furthermore, you're erroneously doing the subtraction again in the second array subscript of array[i-1][charToInt(position[1])-1].
Similarly, as pointed out by Jite and BLUEPIXY, you are doing two extra subtractions on the result of charToInt(position[0]): one in the for loop initializer (i=charToInt(position[0])-1) and one in the first array subscript of array[i-1][charToInt(position[1])-1].
Once you fix that, you might find that you are sometimes incorrectly telling the user that their selection is invalid. This is because you are checking charToInt(position[0]) + slots < r instead of <= r.
As I mentioned in my comment, one of the accesses to array is very probably the culprit behind your segmentation violation, not position[3] == 'N'. The reason you don't see the output of printf("\n%s", "come on"); is that your stdout appears to be line-buffered and there's no end of line to flush it. It is generally automatically flushed on normal program termination, however you're seg-faulting so that doesn't happen.
Finally, these are only the semantic errors I noticed. Stylistically, the code could also stand to be improved. For instance, it seems you're going to be implementing else if(position[3] == 'E', else if(position[3] == 'W', and else if(position[3] == 'S' clauses with similar logic to your if(position[3] == 'N' clause. This increases the likelihood you'll introduce an error by incorrectly copying-and-pasting and also increases your work later when you need to make a change in four places instead of one.
Since the terminology 'Segmentation Fault' I believe you are on Linux machine.
Use gdb to find the cause of error. Here are the steps.
Compile with additional -g flag (ex. gcc -g my_prog.c)
Run debugger: gdb a.out
Use 'list' command to find the line for break point (eg. first line of your function)
Set breakpoint on that line with: b 25 (if 25 is that line)
Run program with 'run' command
Use command 'next' to execute next line of code
Now the execution will pause on that line, you can examine memory, print variable contents
and stuff. But generally you want to determine on which line the execution fails and what was in which variable.
With a little playing with memory, you will easily find where the problem is. Personally, my code wont work with gdb support.
Perhaps segmentation fault at array[i-1][charToInt(position[1])-1]
i:charToInt(position[0])-1 : charToInt('A') - 1 : -1 <- Array out-of-bounds

What's the right way to handle this error checking?

I have a function that should be passed a string with two numbers (as a regex: /-?[0-9]+ -?[0-9]+/) and return the second.
I've decided that the program should do error checking. First, it should test if the string is actually of the desired form; second, it should ensure that the first numbers (the ones that are not returned) are sequential.
Now I've been programming for a long time and this is not a difficult task. (It's made slightly more difficult by the fact that the numbers need not fit into a machine word.) But my question is about how I should do this rather than how I can. All of the solutions I've come up with are somewhat ugly.
I could use a global variable to keep the values in and compare them (or just leave the value there if it's NULL); this seems like The Wrong Thing.
I could pass one or both of the return value and the last/current line's first number by reference and modify them
I could use the return value to give a bool for there was/was not an error
etc.
So any thoughts relating to the proper way to deal with error-checking of this sort in C would be welcome.
This is related to a much more theoretical question I asked on cstheory. For reference, here is the function:
char*
scanInput(char* line)
{
int start = 0;
while (line[start] == ' ' || line[start] == '\t')
start++;
if (line[start] == '#')
return NULL; // Comment
if (line[start] == '-')
start++;
while (line[start] >= '0' && line[start] <= '9')
start++;
while (line[start] == ' ' || line[start] == '\t')
start++;
int end = start;
if (line[end] == '-')
end++;
while (line[end] >= '0' && line[end] <= '9')
end++;
if (start == end)
return NULL; // Blank line, or no numbers found
line[end] = '\0';
return line + start;
}
and it is called like so:
while(fgets(line, MAX_LINELEN, f) != NULL) {
if (strlen(line) > MAX_LINELEN - 5)
throw_error(talker, "Maximum line length exceeded; file probably not valid");
char* kept = scanInput(line);
if (kept == NULL)
continue;
BIGNUM value = strtobignum(kept);
if (++i > MAX_VECLEN) {
warning("only %d terms used; file has unread terms", MAX_VECLEN);
break;
}
// values are used here
}
The traditional solution in C is to use pass by reference (pointers) to return the values your function computes and use the return value for error handling, just like how scanf does this.
int scanInput(char **line_p int *number){
char * line = *line_p;
...
if(something bad happens){
return 1;
}
...
*linep = line + start;
*number = ...;
return 0; //success
}
int main(){
char word[100]; strcpy(word, "10 17");
char *line = word;
int number;
switch(scanInput(&line, &number)){
case 1:
default:
}
}
Extra points:
It might be a good idea to use some enum to give a meaning to the error codes.
If you can use C++ (or similar) exceptions are often the best solution for error handling, since you don't have to fill your code with ifs anymore
Global variables are generaly evil. If you are tempted to use them, consider instead encapsulating the state you need in a struct and passing a pointer to it around. Treat it as a "this" pointer, in the OO sense.
Ultimately, you are going to need to isolate and convert both big numbers in each line. To check that the first number on the line is the one that follows the previous, you will have to keep a record of the last such number found. So, you will probably need a structure such as:
BIGNUM old_value = 0; // See notes below
while (fgets(line, sizeof(line), f) != 0)
{
BIGNUM value1;
BIGNUM value2;
if (ScanDoubleBigNum(line, &value1, &value2) != 0)
...handle line format error...
if (old_value == 0 || are_consecutive(old_value, value1))
{
// OK - valid information found
// Release old_value
old_value = value1;
process(value2);
// Release value2
}
else
...handle non-consecutive error...
}
The are_consecutive() function determines whether its second argument is one greater than its first. The process() function does whatever you need to do with the second value. The ScanDoubleBigNum() function is related to your ScanInput() but it reads two values. The actual code will call another function (call it ScanBigNum()) containing about half of ScanInput() (since that contains essentially the same code twice), plus the conversion that currently occurs in your loop. The code in ScanDoubleBigNum() will call ScanBigNum() twice. Note that ScanBigNum() will need to identify where the scan finishes so that the second call can continue where the first stopped.
I'm taking the liberty of assuming that a BIGNUM is an allocated structure identified by a pointer, so the initialization BIGNUM old_value = 0; is a way of indicating there is no value yet. There is presumably a function to release a BIGNUM. If this is incorrect, then you need to adapt the proposed code to accommodate the actual behaviour of the BIGNUM type. (Is this based on OpenSSL or SSLeay code?)

Resources