1

how can i check if a char variable is empty?
I mean that check with like empty() method with strings, if the string doesn't contain any character stringVar.empty() will result true. How can i check if a char variable doesn't contain a character?
For example, I've a code like this:

// all libraries are included before and code is simplified because it is very long
std::fstream file;
char mychar;

file.open("userselectedfile.txt", std::fstream::in);
if (file.is_open() == true) {
   while (file.eof() != true) {
      // check if mychar is initialized yet (first time that the while execute)
      if (mychar == '') {
         mychar = file.get();
         // do something special beacuse mychar wasn't initialized
         // do something with other files
      } else {
         mychar = file.get();
         // do something else with other files
      }
   }
}
file.close();

This code isn't correct and I don't know how to solve in a nice way, i found a little thing that permise me to bypass the problem but it isn't perfect. For the moment I'm using:

std::fstream file;
char mychar;

file.open("userselectedfile.txt", std::fstream::in);
if (file.is_open() == true) {
   for (int i = 0; file.eof() != true; i++) {
      if (i = 0) {
         mychar = file.get();
      } else {
         mychar = file.get();
      }
   }
}
file.close();

Is this the only way to check if mychar isn't initialized yet? If there is a possibility to check if mychar isn't initialized yet different from the one above, which functions have I to use?

Update 1

Software aim: In this specific case the program I'm building is aimed to delete every comment in a coding source code file that the user (me cause is for me) submit, so i can't use a special character because it can be present on the file, use \0 is a nice idea but i hope that there are others. When I write //do something with ... in my program i continue to read characters till i find comments and I ignore them while creating the new file without them.
BOM: No, files i tested didn't throw me errors apart that the algorithm is a little bugged, but not the part i asked to you.

M. Petri
  • 37
  • 1
  • 9
  • Perhaps you could tell us a bit more about what you're trying to accomplish? Do you want to do something special for the first character you read, or when/if the attempt at reading fails, or what exactly? – Jerry Coffin Aug 17 '18 at 18:55
  • `while (file.eof() != true) {` https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong – drescherjm Aug 17 '18 at 18:55
  • Do you have an error on first 2-4 bytes? I.e [BOM](https://en.wikipedia.org/wiki/Byte_order_mark) in your txt file ? Something like 0xEF | 0xBB | 0xBF ? In fact `char` datatype is actually same thing like `int8_t` in most C/C++ implementations. – Victor Gubin Aug 17 '18 at 19:15
  • For this particular problem: read one character outside the loop, the rest of them inside it. (But you should not leave your variables uninitialised except in extreme circumstances. It causes countless easily avoidable bugs.) – molbdnilo Aug 17 '18 at 19:25

7 Answers7

8

You can't.

In C++, uninitialised variables have an unspecified value, and it is undefined behavior to read from them in any way, so you won't even be able to check what's in it.

You have three options:

  • Give it a value that you know you won't encounter in your file. A \0 might work in your case.
  • Use a separate boolean variable to track if you've read it once.
  • In C++17, use a std::optional<char>.
Etienne de Martel
  • 30,360
  • 7
  • 86
  • 102
4

A char is never empty. It always contains a value even if you don't initialize it. You can't assume any specific value if you don't initialize it, so what you are asking is basically impossible.

In practice, you can initialize a char to NUL. By convention you can pretend that represents the 'empty' value. Once you do that you can test to see if the char contains the empty value, and use that for the basis of your test.

char x = '\0';   // Initialize to 'empty' value
char y = 'a';    // Initialize to a 'non-empty' value

if (x == '\0') std::cout << "x is empty" << std::endl;
if (y == '\0') std::cout << "y is empty" << std::endl;
EvilTeach
  • 26,577
  • 21
  • 79
  • 136
  • Why write `'\0'` when you can write `0`? – ypnos Aug 17 '18 at 19:12
  • No implicit typecast – EvilTeach Aug 17 '18 at 19:30
  • 1
    @EvilTeach -- no implicit type **conversion**. A typecast is always explicit. A cast is something you write in your source code to tell the compiler to do a conversion. – Pete Becker Aug 17 '18 at 20:35
  • The compiler can promote x to be an int before the compare. That promotion is in effect a cast. I have personally observed it in the past, hence I generally use '\0' as opposed to 0. I assume that current compilers will deal correctly in both cases and generate sane code. I am OK with you using 0. – EvilTeach Aug 17 '18 at 23:39
  • A quick test on godbolt shows that for a gcc 86-646 it doesn't matter. for x86-64 msvc pre 2018 it does. – EvilTeach Aug 17 '18 at 23:52
2

std::fstream::get() does not return a char but an int. Apart from the solutions offered by others, you could use int mychar = -1 and check for that.

However I would strongly suggest you reorganize your code so you don't have to do this. In fact, you do not need (and should not use) an extra check for EOF before using get() if you parse the result of get() correctly. It returns an int precisely so that it can return EOF instead of a char value if no character could be read.

Finally, you can also use another overload of get() that takes the target char as an argument like this:

while (file.get(mychar)) { … }

ypnos
  • 45,954
  • 14
  • 88
  • 130
2

If you have a variable that can either hold a value or not then std::optional is made exactly for that purpose. As an example:

#include <iostream>
#include <optional>

void print_or_not(std::optional<char> x){
    if (x) std::cout << x.value();
}

int main() {
    std::cout << "uninitialized \n";
    std::optional<char> x;
    print_or_not(x);
    std::cout << "initialized \n";
    x = 'x';
    print_or_not(x);
}

prints

uninitialized 
initialized 
x
463035818_is_not_a_number
  • 64,173
  • 8
  • 58
  • 126
1

Instead of trying to determine if the mychar hasn't been used yet lets restructure the loop to handle that for you. If you use a for loop you can declare a variable and we can use that to track if it is the first iteration of the loop. That would make the code look like

for(bool first_iteration = true; file.eof() != true;) {
   mychar = file.get();
   // check if this is the first iteration
   if (first_iteration) {
      first_iteration = false;
      // do something special beacuse this is the first iteration
   }
   // do something with other files
}
NathanOliver
  • 150,499
  • 26
  • 240
  • 331
0

You cannot. If you want to do something differently the first time the loop executes, use a boolean flag:

bool first = true;
while (file.eof() != true) {
    if (first) {
        // do something
        first = false;
    } else {
        // do something else
    }
}

If you truly want a variable that may or may not contain a char value, use std::optional<char>.

Brian Bi
  • 91,815
  • 8
  • 136
  • 249
-2

You can use the following code to check if a char variable is undefined (not initialized):

char c;

if(c == NULL)
{
    cout<<"Your character doesn't have any value";
}

else
{
    cout<<"the character you entered is:" << c;
}
  • Welcome to StackOverflow! Please use the code format tag to format your answer as code so it is easier to read. Can you also elaborate why and how your code works? – DBX12 Aug 23 '18 at 06:32
  • 1
    This code doesn't do what you claim. A `char` variable always contains a value. If the variable is uninitialized then the value is unspecified. In addition, the code in your `else` branch is wrong. Adding `c` to a string literal doesn't perform concatenation. You should change the `+` to `< – Blastfurnace Aug 28 '18 at 00:44