-2

Instead of initialising my variable in the struct with a numerical value of 0, I tried to use scanf such that it would read in my input values directly. It doesn't work but I can't figure out why?

I was wondering if it could be related to the fact that using &(p1.first) is invalid because the memory space had not been allocated? If so, is the only way to update the value of my struct variables via rewriting the scanf statements after the initialisation such as in the commented code below?

#include <iostream>

using namespace std;

typedef struct {
  int first;
  int second;
} score;

int main() {
  score p1 = {
    p1.first = scanf("%d", &(p1.first)),
    p1.second = 0,
  };

  /* I know the following works:
  score p1 = {
    p1.first = 0,
  };
  scanf("%d", &(p1.first));
  */

  printf("%d", p1.first);
}

When input is 2, I expected to get 2 as well, but regardless of the input value I tried, printf prints 1.

y.han
  • 23
  • 3
  • 4
    You're misusing the return value of `scanf`. `scanf` already stores the result in the location you provided in the second parameter. On success, the function returns the number of items of the argument list successfully filled. See http://www.cplusplus.com/reference/cstdio/scanf/ – Robert Harvey Jan 10 '19 at 16:07
  • 1
    Why is this being voted down? OP provided an example and described expected results vs actual results. – nicomp Jan 10 '19 at 16:26
  • @nicomp People are getting tired of what they perceive to be basic, relatively silly mistakes. I'm not saying that's a valid reason to downvote (it's not) but I suspect that's kind of what's going on. Perhaps more pertinently, the OP already has the correct solution and it's not entirely clear what they're trying to achieve with the [broken] alternative. Again, though, that's probably not a great reason for a cumulative -4... – Lightness Races in Orbit Jan 10 '19 at 16:29
  • @LightnessRacesinOrbit Good points. The downvotes seem to contradict our stated goal of nurturing new SO members. I would differ with you that what OP is trying to achieve is unclear: he/she wants an explanation of why something works as it does. PS: You hate the ternary operator? ;) – nicomp Jan 10 '19 at 16:33
  • 3
    @nicomp Well, nurturing new members and accepting low quality questions are two different things. The former does not imply the latter. You can't avoid downvoting a question just because its author is new: that defeats the core purpose of the website. But personally I think this is a new member with a reasonable quality question. – Lightness Races in Orbit Jan 10 '19 at 16:38
  • @nicomp & LightnessRacesinOrbit Thank you for your words, I was slightly taken aback by the downvotes at first, but it's alright. Regarding what I was trying to achieve with the wrong method (why I made the mistake in the first place), I was wondering if there was a shorter and more direct one-liner to initialise my variable in struct, instead of the multi-lined one which I have commented out. It's one of my first few attempts at using scanf so apologies in advance for potentially novice questions. – y.han Jan 10 '19 at 16:56
  • @y.han Remember to accept an answer. :) – nicomp Jan 10 '19 at 17:06
  • @y.han A completely worthy reason (and, indeed, as I allude to in my answer, sometimes _necessary_)! Perhaps consider expressing this in your question to make it more coherent. – Lightness Races in Orbit Jan 10 '19 at 17:20

2 Answers2

4

scanf returns the number of items scanned. In this case, the way you described your particular input, it's always 1. That's where the 1 comes from.

nicomp
  • 4,344
  • 4
  • 27
  • 60
2

You can initialise members from expressions. An expression is a bit of code that evaluates to something. A bit of code that is a call to a function evaluates to what the function call returns.

scanf doesn't return the value you want, but a count of the number of arguments successfully parsed (read the documentation!). That's not what you want to be using. You have then tried to name the member in scanf's "out parameter" slot, but that doesn't work because (a) the object doesn't exist yet, and (b) you're literally about to initialise the member from another value because (c) the out parameter has no effect on what the expression evaluates to.

In short, this can't work. You can wrap the call into a specific new function that does return what you needed:

#include <cstdio>

struct score {
  int first;
  int second;
};

int ReadANumber()
{
   int number;

   const int r = std::scanf("%d", &number);
   if (r > 0 && r != EOF)
     return number;

   // some fallback, or you could throw an exception!
   return -1;
}

int main() {
  score p1 = { ReadANumber(), 0 };
  printf("%d", p1.first);
}

(live demo)

Notice that I have also corrected your header include, removed the assignments in the initializer (weird; works for arcane reasons but don't do that), de-C-ised your class definition, and removed using namespace std as we don't like that.

…or stick with the working solution you have in your comments (though this precludes declaring p1 as const!).

user4581301
  • 33,082
  • 7
  • 33
  • 54
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Thanks for the answer! I would like to clarify something: May I know the reasons to the corrections you have made (in italics) at the end? Particularly why we don't use namespace std and what did you mean by the assignments in the initializer? – y.han Jan 12 '19 at 03:37
  • @y.han You can look these things up, e.g. https://stackoverflow.com/q/1452721/560648 and read the bit in your book about initializing! Though if you wanted to write a new, separate question specifically about the way you'd been using the initialiser I'd be happy to answer it – Lightness Races in Orbit Jan 12 '19 at 16:47