Uint8_t array not being passed from a if statement

I have a routine that compares two variables X and Y and allocates a value to a uint8_t but when I try to use the text in the uint8_t I get a message that it was not declared. Please see my code.

if (!x && !y) uint8_t data[] = "First argument";

else if (!x && y) uint8_t data[] = "Second argument";

else if (x && !y) uint8_t data[] = " Third argument";

else if (x && y) uint8_t data[] = Fourth argument";

Serial.println((char)data);

Error is "data was not declared in this scope".

The array in your code is declared local to if statement and can't be used outside of it.
In full notation, your code equivalent to this:

if (!x && !y) 
  {
   uint8_t data[] = "First argument";
  }

As soon as the code goes beyond the closing bracket, the array is destroyed.

The correct approach is to make the data array global, allocate memory for it in advance, and then fill it with the desired text, for example using the strcpy() method:

const char *source = "First argument"; // Static message
char data[20];                         // Destination array

if (!x && !y) 
  {
   // Copy the static text to the data array
   strcpy(data, source, sizeof(source) );
  }

There might not be a need for "extra" memory.
How about:

char *data="";
if (!x && !y) data = "First argument";
else if (!x && y) data = "Second argument";
else if (x && !y) data = " Third argument";
else if (x && y) data = "Fourth argument";

Serial.println(data);
char *data = "";

void setup(void) {
  Serial.begin(115200);
  randomSeed(analogRead(A0));

  byte x = random(2);  Serial.print(x);
  byte y = random(2);  Serial.print(y);

  switch (x << 1 | y) { // SHIFT then bitwise OR
    case 0: data = " Zro"; break;
    case 1: data = " One"; break;
    case 2: data = " Two"; break;
    case 3: data = " Tre"; break;
  }
  Serial.println(data);
}

void loop(void) {}

What's odd is that without the braces, the variable still goes "out of scope", although technically there was no scope for it to go out of.

So it kinda is and kinda is not a scope thing.

The error message is unsatisfactory, and no warnings (at least at common level) issue.

Once again you can do stuff that looks plausible but don't end up doing what you want.

As has been pointed out, there are work-arounds to the OP's entirely plausible attempted method.

I would have winced seeing the code, but assumed the nearest { embracement } would be involved, that seems not to be the case.

a7

After every if or the final else with no condition is a block. Without braces, it's a single statement. C/C++ allows

  if (condition) doSomething();
  else doSomethingElse();

with each semicolon as a statement terminator: the else looks less related. With

  if (millis() % 3) uint8_t foo{ 3 };
  else uint16_t foo{ 300 };

there are unused variable warnings for each line, with Warnings set at More and All (but not Default); and no "conflicting declaration" error for the differing types because they are in separate blocks. (Brace initialization will trigger a narrowing conversion error if there is overflow; plain old equal-assignment might generate a warning.)

The compiler would be happier if that was declared const char * -- those strings might not be writable, and any duplicates likely pooled. This works fine to point at one of them and read from there. If the intent is to modify that buffer, you'll want to make a copy.

Nothing odd as for me.
As I mentioned above, the braces around the single line can be omitted, but from the syntax point of view they still are here .

Thank you all for your replies, I have learnt a lot from this and have now got my code working.

What about

if (!x && !y) Serial.println( F("First argument") ) ;
else if (!x && y) Serial.println( F("Second argument") ) ;
else if (x && !y) Serial.println( F("Third argument") ) ;
else if (x && y) Serial.println( F("Fourth argument") ) ;