long long int don't take long int well - c++

When a friend of mine asked me to debug the problem with a console game project I had found a weird conversion of fprintf in C that I can't figure out. The project was required to keep track of all the information, including scores and update time to a .txt file using C.
-Initialization
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
.
.
.
// in main
time_t timer;
time (&timer);
int num=0,c;
scanf(" %s %ld", inputname,c);
fscanf(fp, "%d", &num);
num++;
char **name;
long *times;
ull *score;
name = new char *[num];
for(int i=0; i<num; i++){
name[i] = new char[MAX];
}
times = new long [num];
score = new ull[num];
//new data
name[num-1] = inputname;
score[num-1] = c;
times[num-1] = timer;
-The I/O parts
.
.
.
// input from file after dynamic variables have fix size
for(int i=0; i<num-1; i++){
fscanf(fp, " %s%d", name[i], &score[i]);
fscanf(fp, "%ld", &times[i]);
}
fseek(fp , 0 , SEEK_SET);
fprintf(fp, "%d\n", num);
//print back to fp
for(int i=0; i<num; i++){
fprintf(fp, "%s %ld ",name[i], score[i]);
fprintf(fp, "%ld\n",times[i]);
}
Problem. if I change
fprintf(fp, "%s %ld ",name[i], score[i]);
fprintf(fp, "%ld\n",times[i]);
to one-line
fprintf(fp, "%s %ld %ld\n",name[i], score[i],times[i]);
the output file will have
NAME1 SCORE1 TIMEINLONG1
NAME2 SCORE2 0
NAME3 SCORE3 0
.
.
.
instead of
NAME1 SCORE1 TIMEINLONG1
NAME2 SCORE2 TIMEINLONG2
.
.
.
After some trying, I found that by reversing the order of scores and times
fprintf(fp, "%s %ld %ld\n",name[i], times[i],score[i]);
I have a correct output
NAME1 TIMEINLONG1 SCORE1
.
.
.
again.
So, how exactly does C do with output stream. I thought the compiler collect the argument in "..." to assemble a string, then flush it to outputstream. Obviously it ignored the time[i] after the first (time[0]).
Is it the problem of the way I intialize times[]?
Or is it the problem with fprintf()?
Apology for such a lengthy page, but I'm really confused about the fprint now.
Solved
edit title from "fprintf with dynamic memory" to "long long int don't take long int well, vise versa."
The problem was not on the dynamic memory things(Sorry I didn't know), but was the type that I used to get and put data in printf, fprintf, scanf, fscanf. According to #Adrian Mole , the mismatch assign long int to a long long int type variables was undefined behavior, and the following I/O action will not be correctly done. It seems that even long long int have more space than those of long long, it is not compatible.
No
long long int c;
scanf("%d",&c);
printf("%d",c);
//or
scanf("%ld",&c);
printf("%ld",c);
Yes
long long int c;
scanf("%lld",&c);
printf("%lld",c);

You have here a classic example of "undefined behaviour!" The variable that is score[i] is (assuming a reasonable definition of the type ull) an unsigned long long int (possibly/probably 64-bits) but both the scanf and 'offending' printf calls use the %ld format specifier (possibly/probably referring to a 32-bit variable).
When printf is called with a "mismatch" between the format specifier and the given argument, you are in undefined behaviour territory!
Fix the issue by specifying the %llu format for the corresponding score[i] argument! For example, in place of:
fprintf(fp, "%s %ld %ld\n",name[i], score[i],times[i]);
use:
fprintf(fp, "%s %llu %ld\n", name[i], score[i], times[i]);
// score[i] is ull ^ | ^ OK - times[i] is (signed) long!
Feel free to ask for further clarification and/or explanation.

The problems start at the following lines:
int num=0,c;
scanf(" %s %ld", inputname, c);
First, you should write &c instead of c as the last parameter. Since scanf writes into its parameters, it should receive addresses of parameters (except strings, I am too lazy to explain why).
Second, since c is int, you need %d, not %ld. Be careful with sizes.
As for your fprintf - again, be careful with sizes. Since score is ull*, and I assume that ull means unsigned long long, you need to print it with %llu format, not %ld. (Note - Andrian Mole also pointed this piece, and posted his answer slightly before I posted mine.)

Another error is:
name[num-1] = inputname;
That reassigns the pointer to heap allocated memory and causes a memory leak. inputname array should be copied into name[n] array, e.g.,
snprintf(name[num-1], MAX, "%s", inputname);
scanf %s may overflow its destination array argument, unless you hard-code the destination size, e.g.:
#define MAX 256
int num=0,c;
char inputname[MAX];
scanf("%256s %d", inputname, c);

Related

Converting from base 10 to any base between 2 and 36

I'm writing a C++ code that converts an unsigned base 10 integer to any other base between 2 and 36. I haven't coded in a while so I'm kind of re-learning everything. My questions are: how can I keep it to just printf, without the cout at the end, and still display the ascii value. And is it possible to make it simple(basic).Sorry if I didn't format properly.
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string>
using namespace std;
int main()
{
int InitialNum, BaseNum, Num, x;
string FinalNum, Temp;
printf("Enter an unsigned integer of base ten: \n");//Prompt user for input
scanf_s("%d", &InitialNum);
printf("Enter the base you want to convert to (min2, max36): \n");
scanf_s("%d", &BaseNum);
x = InitialNum; //save the base 10 number to display at the end
while (InitialNum != 0) //continue dividing until original input is 0
{
Num = InitialNum % BaseNum; //save remainder to Num
int ascii = 48; //declare conversion variable (from int to char)
for (int i = 0; i < 32; ++i)//for loop converts Num from int 0-15 to char '0'-'9', 'A'-'F'
{
if(Num == i)
Temp = ascii;
ascii += 1;
if (ascii == 58)//skip from 9 to A on the ascii table and continue
ascii = 65;
}
FinalNum = Temp + FinalNum;//add to the final answer(additions to the left)
InitialNum /= BaseNum; //the initial base10 number gets divided by the base and saved as the quotient
}
printf("The number %d converted to base %d is:", x, BaseNum);
cout<<(FinalNum);
system("PAUSE");
return 0;
}
In order to output a std::string with printf you have to serve it to printf as a null-terminated string, the C style string. Or, well, you don't absolutely have to: you could print one character at a time. But it's most easy and practical to serve it as a null-terminated string.
You can do that via the .c_str() member function, hence:
printf( "%s\n", FinalString.c_str() );
Note that using std::string can be expensive at this low level of things, due to the dynamic allocation(s). E.g., (http://www.strudel.org.uk/itoa/), timing various implementations of itoa, found a 40x penalty.

Convert a String to an int and store the result in a variable

int Units;
void input(int i) {
char temp[50];
printf("Enter class id for #%d > ", i + 1);
readLine(ClassID);
printf("Enter Name for #%d > ", i + 1);
readLine(ClassName);
printf("Enter Description for #%d > ", i + 1);
readLine(Description);
printf("Enter pre-reqs for #%d > ", i + 1);
readLine(PreReqs);
printf("Enter units > ");
readLine(temp);
// Write a method to convert String temp into an integer and store it in the Units field
I think I need to do something with a nested loop but I am not exactly sure how to go about the conversion please help.
Use the atoi() function from cstdlib (you will need to include cstdlib at the top of your file):
units = atoi(temp);
It converts a char array into an integer. See here.
You can also use strtol() which allows for error checking, see here for details. Credit: #NathanOliver

Very anomalous behaviours by C++ compiler

I have the following code. In the function xyz(int from, int to, int i). I am printing the value of i and i*2+1. But I am getting unexpected output with i = 1 and i*2+1 = -1.
The function xyz2() is exactly the same except that I have uncommented a dummy function call and I am getting the expected output with i = 0 and i*2+1 = 1. Please see the output as I have explained it. Also I would mention that I get the same output on my local machine.
Why is this happening?
#include <stdio.h>
#include <stdlib.h>
long long arr[2];
long long xyz(int from, int to, int i);
long long array[200000];
long long xyz2(int from, int to, int i);
long long foo(){return 141;}
int main(){
int n=2;
arr[0] = -4;
arr[1] = 5;
xyz(0, 1, 0);
printf("\n\n");
xyz2(0, 1, 0);
return 0;
}
long long xyz2(int from, int to, int i){
if(from==to){
return arr[to];
}else{
int mid = (from+to)/2;
array[i*2+1] = xyz2(from, mid, i*2+1);
array[i*2+1] = foo();
printf("%d %d\n", (i*2)+1, i);
return 100000;
}
}
long long xyz(int from, int to, int i){
if(from==to){
return arr[to];
}else{
int mid = (from+to)/2;
array[i*2+1] = xyz(from, mid, i*2+1);
//array[i*2+1] = foo(); // The above function xyz2 gives the
//correct results on uncommenting this line
printf("%d %d %d\n",array[i*2+1], (i*2)+1, i);
return 100000;
}
}
printf("%d %d %d\n",array[i*2+1], (i*2)+1, i);
The first data argument is a long long. You need to change your format string to match:
printf("%lld %d %d\n",array[i*2+1], (i*2)+1, i);
The reason you're getting weird behaviour when the wrong conversion specification is used is because the behaviour is undefined:
C99 §7.19.6.1/9 If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
This comes from the specification for fprintf, which printf is defined in terms of. The C99 standard is normative for C++11.
This line in xyz2(..):
printf("%d %d %d\n",array[i*2+1], (i*2)+1, i);
is NOT the same as this line in xyz(..)
printf("%d %d\n", (i*2)+1, i);
Changing the commented out line changed the result as follows:
With Line Commented
-4 1 0
1 0
With Line Uncommented
141 1 0
1 0
I don't seem to be getting any strange output (I think) using XCode 5....but I AM getting warnings about the format of the printed string:
printf("%d %d\n", (i*2)+1, i);
should be
printf("%lld %d\n", (i*2)+1, i);
Using long long requires a special print format, I believe. This could be the problem...

Using Char in an if statement C++

Folks, I'm trying to use an 'if' statement with a char variable, but it doesn't seem to notice when the 'yes' condition is met. I don't know if there's a way to do this without the array. Here's my code below. Any help is much appreciated.
// Running times calculator
# include <iostream>
# include <math.h>
using namespace std;
int main ()
{
float cTime;
float gTime;
float cDist;
float gDist;
float min;
float sec;
float cMin;
float cSec;
float p1000;
char response[1];
int blank;
printf ("Welcome to the running times calculator.\n\nEnter your completed race distance in metres: \n");
scanf ("%f", &cDist);
printf("Enter your completed race time. Type minutes, hit enter. Type seconds, hit enter\n");
scanf ("%f" "%f", &cMin, &cSec);
cTime = cSec+(60*cMin);
p1000 = pow(1000/cDist,1.1)*cTime;
printf ("Would you like to enter another race time to improve prediction accuracy? \n");
scanf ("%s", &response);
if(response == "yes")
{
printf ("Enter your completed race distance in metres: \n");
scanf ("%f", &cDist);
printf("Enter your completed race time. Type minutes, hit enter. Type seconds, hit enter\n");
scanf ("%f" "%f", &cMin, &cSec);
cTime = cSec+(60*cMin);
p1000 = ((pow(1000/cDist,1.1)*cTime)+p1000)/2;
}
printf ("What is your goal race distance in metres? \n");
scanf ("%f", &gDist);
gTime = pow(gDist/1000, 1.1)*p1000;
min = gTime/60;
sec = remainder(gTime,60);
if (sec < 0)
{
sec = sec + 60;
min = min - 1;
}
printf ("Your predicted time for a race of %.0f metres is %.0f minutes and %.0f seconds", gDist, min, sec);
scanf("%f", &blank);
return 0;
}
You got a few problems with the way you treat your char array.
char response[1]; You create an char array that consists of one character here but then you treat it as a string in these lines:
scanf ("%s", &response);
if(response == "yes")
also note that you can't simply compare a char array and a string literal with == all you'd do would be comparing addresses. You'd either have to use strcmp() or better use std::string.
Didn't check all the code, but you use an
operator ==
that doesn't work with a char [], it's for string
use strcmp instead.

why does printf show a 0 for vector size when cout shows the correct size?

I don't get why I get 0 when I use printf and %d to get the size of my vector:
vector<long long> sieve;
int size;
...
//add stuff to vector
...
size = sieve.size();
printf("printf sieve size: %d \n", size); //prints "printf sieve size: 0"
std::cout << "cout sieve size: ";
std::cout << size;
std::cout << " \n ";
//prints "cout sieve size: 5 (or whatever the correct sieve size is)"
If I iterate through the vector via
if(i=0;i<sieve.size();i++)
I get the correct number of iterations.
What am I doing wrong or what is up with printf? size() returns an int right??
Here's my entire little script:
#include <iostream>
#include <vector>
#include <stack>
#include <math.h>
int main (int argc, char * const argv[]) {
unsigned long long answer = 0;
unsigned long long cur = 2;
std::vector<long long> sieve;
unsigned long long limit;
unsigned long long value;
unsigned int i;
int size;
bool isPrime;
std::cout << "Provide a value to find its largest prime factor: ";
std::cin >> value;
limit = ceil(sqrt(value));
sieve.push_back(2);
while(cur++ < limit){
isPrime = true;
sieve.begin();
for(i=0; i<sieve.size();i++){
if(!(cur % sieve[i])){
isPrime = false;
break;
}
}
if(isPrime){
if(!(value % cur)){
std::printf("Is prime factor: %d\n", cur);
sieve.push_back(cur);
answer = sieve[sieve.size() - 1];
size = sieve.size();
std::printf("current last: %d sieve size: %ld\n", answer, size);
for(i=0; i<sieve.size();i++){
std::printf("sieve iter: %d sieve val: %d\n", i, sieve[i]);
std::cout << size;
std::cout << " wtf\n";
}
}
}
}
answer = sieve[sieve.size() - 1];
size = sieve.size();
std::printf("Limit: %d Answer: %d sieve size: %ld\n", limit, answer, size);
return 0;
}
Now, with the complete source, it is clear.
You declared:
int size;
Then you used:
std::printf("current last: %d sieve size: %ld\n", answer, size);
std::printf("Limit: %d Answer: %d sieve size: %ld\n", limit, answer, size);
If size is int, you should use "%d", not "%ld". A good compiler would have warned you about this. GCC gives these warnings for your original version:
test.cpp: In function ‘int main(int, char* const*)’:
test.cpp:17: warning: converting to ‘long long unsigned int’ from ‘double’
test.cpp:30: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long long unsigned int’
test.cpp:34: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long long unsigned int’
test.cpp:34: warning: format ‘%ld’ expects type ‘long int’, but argument 3 has type ‘int’
test.cpp:36: warning: format ‘%d’ expects type ‘int’, but argument 3 has type ‘long long int’
test.cpp:45: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long long unsigned int’
test.cpp:45: warning: format ‘%d’ expects type ‘int’, but argument 3 has type ‘long long unsigned int’
test.cpp:45: warning: format ‘%ld’ expects type ‘long int’, but argument 4 has type ‘int’
This tells a lot.
You should declare size as:
std::vector<long long>::size_type size;
Then you should use it as:
std::printf("current last: %llu sieve size: %llu\n", (unsigned long long) answer, (unsigned long long) size);
std::printf("Limit: %llu Answer: %llu sieve size: %llu\n", (unsigned long long) limit, (unsigned long long) answer, (unsigned long long) size);
Of course, using iostream avoids you these problems, specially the ugly casting in printf() to transform size to a type known to printf.
This is screwing up because you've got:
unsigned long long answer = 0;
int size;
and you call printf with:
std::printf("current last: %d sieve size: %ld\n", answer, size);
Both of your format strings are wrong:
You're passing answer to printf and formatting it %d, but it should be %lld, since it's declared unsigned long long.
You're passing size with %d instead of %ld. Since size is and int, it should be %d.
When those args get passed to printf, it's printing the first 32 bits of answer for the first %d and the second 32 bits (or more, past the end!) of answer for the %ld. This is not what you want.
If you compile with -Wall your compiler should warn you about this kind of thing. Pay very close attention to the warnings!
Looks crazy. Because size is declared as "int size", printf("...%d") is definitely correct. It can't be about size_t being different than "int" in size, because you explicitly declare "size" as int, and cout << ... size ... works correctly.
Have you checked that you have included ? It might be that without proper declaration on your system printf works "wrong".
Your problem is that answer is defined as a long long and you only printf it with a %d.
printf is a varargs function and in C that means the compiler doesn't know what arguments you passed into the function. It cannot do its normal type conversions and it has to trust its user to get the format arguments right, or the arguments will not be pulled off the call stack properly.
You didn't get it right.
vector sizes are size_t, which I believe is usually a long...
Couldn't say why printf isn't working, though.
The size() method returns size_t, which depends on your c++ implementation. When you try to printf("%d"), you're telling the library to expect an int, which isn't necessarily the case; it then takes an int from the call stack, which is taking only the high-order bytes of the size_t.
What you'll need to do is force the return value size() to a known data type with casting:
printf("%d", (int) size)
What's the hardware you're running on? Odds are that size is a different type than you think. Print sizeof(size) and check, or try a %ld. If you have a big-endian machine like a PPC, size is a long, and you print a %d, you get the all-zeros end of the long.
update
Okay, this is what I get with an Intel Mac mini, 10.5:
$ cat trySize.C
#include <iostream>
#include <vector>
int main(){
std::cout << "sizeof(size_t): "
<< sizeof(size_t)
<< std::endl ;
std::vector<long long> sieve ;
std::cout << "sizeof(sieve.size()): "
<< sizeof(sieve.size())
<< std::endl;
printf("sizeof(sieve.size()) (printf): %d\n", sizeof(sieve.size()));
return 0;
}
$ g++ trySize.C
$ ./a.out
sizeof(size_t): 4
sizeof(sieve.size()): 4
sizeof(sieve.size()) (printf): 4
$
You probably should start breaking the code up into smaller pieces and trying them; there's something hinky here.
This will work:
std::printf("current last: %**lld** sieve size: %ld\n", answer, size);
The problem is that answer is a long long (a 64 bit integer) and %d expects a 32bit integer. So size doesn't get printed. You will need to use %lld.
For more information on format strings for printf check out:
http://en.wikipedia.org/wiki/Printf