0

I'm working on program which input looks as follows:

3.14 (it's variable stored in union)
4 (number of calls)
int (asked types to return)
long
float
double

On output should i get:
1078523331
1078523331
3.140000
0.000000

Full instruction to this task
My program works except on double case: instead of giving me any output program gives me none. Can anyone explain me why? Here is my code.

#include <stdio.h>
#include <string.h>
#define SIZE 1000
#define CHARLENGTH 6
union Data {
  int i;
  long long l;
  float f;
  double d;
};
int main(){
  union Data x;
  char types[SIZE][CHARLENGTH];
  int n;
  scanf("%f",&x.f);
  scanf("%d",&n);
  for(int i = 0;i<=n+1;i++){
    fgets(types[i],CHARLENGTH,stdin);
    types[i][strcspn(types[i],"\n")] ='\0';//removing newline
  }

  for(int i = 1;i<=n+1;i++){
    if(strcmp(types[i], "int") == 0){
      printf("%d\n",x.i);
    }
    else if(strcmp(types[i], "long") == 0){
      printf("%lli\n",x.l);
    }
    else if(strcmp(types[i], "float") == 0){
      printf("%f\n",x.f);
    }
    else if(strcmp(types[i], "double") == 0){
      printf("%lf\n",x.d);
    }
  }

}
timrau
  • 22,578
  • 4
  • 51
  • 64
Mateusz
  • 3
  • 1
  • `x.d` is uninitialized, and so to try and read it will invoke [undefined behaviour](http://en.cppreference.com/w/cpp/language/ub). You could change `union Data x;` to something like `union Data x = { 1078523331, 1078523331, 3.20f, 0.0 };` – George Jan 13 '17 at 18:08
  • Not exactly, @George. It is true the `x` is not initialized, but a value is assigned to it via the first `scanf()`. And if it *were* initialized, one would ordinarily provide only one initializer element, since it's a *union*. There is a fine point here: supposing that `sizeof(double) > sizeof(float)`, setting the value of `x.f` results in *unspecified* values for some of the bytes of `x.d`. But that's a different situation from an unintialized object having an *indeterminate* value. Use of the later produces UB, but use of the former does not necessarily do the same. – John Bollinger Jan 13 '17 at 18:38

2 Answers2

1

You do not allow sufficient space in array types for a six-character string such as "double", because you need an extra byte for the terminator. Because you have used fgets() in a reasonable way, however, you have saved yourself from overrunning the bounds of that array -- fgets() just stops reading after the fifth character of "double", and appends a terminator. Therefore, what actually gets stored is "doubl". Naturally, that compares different from "double", so no corresponding output is produced.

  • In the first place, you should increase CHARLENGTH to at least 7. Doing so will take care of your immediate problem.

  • You should also consider adding a final else clause inside your loop that prints out a diagnostic message in the event that none of the other cases is satisfied. Such a message could have clued you in to what's going on.

  • for robustness, you might consider making sure to read and discard any trailing junk on the type lines; as it is, even trailing whitespace after one of the shorter type names will screw up your matching.

  • Perhaps it's respondent to the exercise as it is, but your program would be a lot more user friendly if it prompted for each input item.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
0

Three Four quick observations:

0) As a minimum, the main function should be: int main(void).

1) Because C strings are defined as an array of char terminated with NULL, the string "double" requires a buffer with space for 7 char to contain it.

|d|o|u|b|l|e|\0|    //includes NULL char termination

Change

#define CHARLENGTH 6   

to

#define CHARLENGTH 7  

2) Because it is not clear from the cmd line prompts in the running program what items are to be entered, if one of the string types, eg "double", is not entered, the line:

fgets(types[i],CHARLENGTH,stdin);  

will not do as it is intended. Suggest adding some printf statements with instructions for what to enter for all 3 entries per line.

3) types is not initialized before use.
This can be addressed by simply initializing like this:

memset(types, 0, SIZE*CHARLENGTH);   

or even simpler:

char types[SIZE][CHARLENGTH] = {0}; 

A comparison of what the memory looks like by the time it gets to the fgets statement, uninitialized, or initialized (by either method): ![enter image description here

Community
  • 1
  • 1
ryyker
  • 22,849
  • 3
  • 43
  • 87