Confusion on proper use of char syntax

Good Evening All,

I am a little confused on when and where to use the different variation of char.
The bottom code is everything I have so far. My code below seems to be doing what I want...for now, but I may not be using the syntax's correctly.

The below snippet is used to store names that change based on what RFID card is scanned and date and time. These names will be of set size using sprintf and the names will stay consistent in length. Am I using Char correct here?

  • "filename" stores the date.txt (i.e. 20200622.txt). A new file is created on my SD card daily based on the RTC. will always be in the format "yyyymmdd.txt".
  • "dateandtime" is used to compile the date and time for writing to the SD card and displaying in Serial Print. Will always be in the format: "yyyy/mm/dd, hh:mm".
  • "dailytruckfile" is not yet used in my code, but makes a file name for individual RFID tags and the file name changes daily based on the date (i.e. 202006227001....makes todays file for RFID tag 7001) (eventually will be used to count the number of scans per day using a file size comparison of before and after writing to the file) This will always be a 12 digit number, is an array of 13 the correct size?
  • "lifetimetruckfile" is not yet used in my code, but makes a file name for individual RFID tags for the lifetime the scanner is used (i.e. file name for RFID tag 7001) (eventually will be used to count the number of scans stored on the SD card using a file size comparison of before and after writing to the file) This will always store a 4 digit number, is an array of 5 the correct size?
char filename[13];
char dateandtime[17];
char dailytruckfile[13];
char lifetimetruckfile[5];

In the below snippet the "const char name" was used from another code I referenced, but a little confused on the nomenclature and why this uses a "const char" and the "" on the name. This returns the information i want consistently, but not sure why. Any insight would be great on this one. The code below reads the RFID and determines which card was scanned. The "char *nametocard = "" is something I added in to name nametocard a global variable I can use in other portions of the code, but may not be the correct use.

struct USER
{
  unsigned long ID;
  const char *name;
} Users[] =
{
  {0x734AD60, "7100"},
  {0xE4429C22, "7101"},
};
const byte UserCount = sizeof Users / sizeof Users[0];

char *nametocard = "";

There are a couple of other places where Char and Char *... are used, but want to understand what that is telling the program so I can make sure things will run consistently and without messing up when I deploy this RFID scanner in the field.

#include <MFRC522.h> // for the RFID
#include <SPI.h> // for the RFID and SD card module
#include <SD.h> // for the SD card
#include <RTClib.h> // for the RTC
#include <Adafruit_NeoPixel.h>

// define pins for RFID
#define CS_RFID 53
#define RST_RFID 9

// define select pin for SD card module
#define CS_SD 48



// Create a file to store the data
File myFile;

char filename[13];
char dateandtime[17];
char dailytruckfile[13];
char lifetimetruckfile[5];

// Instance of the class for RFID
MFRC522 rfid(CS_RFID, RST_RFID); 

// Variable to hold the tag's UID
String uidString;

// Instance of the class for RTC
RTC_DS1307 rtc;


//Truck Numbers and tag ID
struct USER
{
  unsigned long ID;
  const char *name;
} Users[] =
{
  {0x734AD60, "7100"},
  {0xE4429C22, "7101"},
};
const byte UserCount = sizeof Users / sizeof Users[0];

char *nametocard = "";

int loadcount = 0;
int newloadcount = 1;


// Pins for LEDs and buzzer
const int buzzer = 5;
#define LEDpin 6

Adafruit_NeoPixel led = Adafruit_NeoPixel(1, LEDpin, NEO_GRB + NEO_KHZ800);

/////////////////////////////////////////////////////////////////////Program Setup/////////////////////////////////////////////////////////////////////

void setup() {
  
  led.begin(); //initialize LED 
  led.show(); // Initialize all pixels to 'off'
  pinMode(buzzer, OUTPUT); // Set buzzer as an output

  
  Serial.begin(9600);//initialize serial port at 9600 baud rate
  while(!Serial); //wait for serial to initialize before proceeding
  
  SPI.begin(); // initilize SPI bus
  
  rfid.PCD_Init(); //initialize RFID

  // Setup SD card
  Serial.print("Initializing SD card...");
  if(!SD.begin(CS_SD)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  // Setup for the real rime clock  
  if(!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while(1);
  }
  else {
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  if(!rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
  }
}

/////////////////////////////////////////////////////////////////////Main Loop/////////////////////////////////////////////////////////////////////

void loop() {
  DateTime now = rtc.now();
  
  sprintf(filename, "%04d%02d%02d.txt", now.year(), now.month(), now.day()); //creates file name for saving daily data in the format yyyymmdd.txt
  
  //Look for new cards
  if(rfid.PICC_IsNewCardPresent()) {
    readRFID(); //if new card is found, read the RFID
  }
  delay(10);
}

/////////////////////////////////////////////////////////////////////Read RFID Card/////////////////////////////////////////////////////////////////////

void readRFID() {
  
  if(!rfid.PICC_ReadCardSerial()){
    Serial.println("Please Scan RFID Tag Again");
    return;
  }


  unsigned long UIDVal = rfid.uid.uidByte[0];
  UIDVal = (UIDVal << 8) | rfid.uid.uidByte[1];
  UIDVal = (UIDVal << 8) | rfid.uid.uidByte[2];
  UIDVal = (UIDVal << 8) | rfid.uid.uidByte[3];

  Serial.print("Tag UID: 0x");
  Serial.println(UIDVal, HEX);

  boolean authorized = false;
  char *name = "";
  
  for (int i = 0; i < UserCount; i++)
  {
    if (UIDVal == Users[i].ID)
    {
      authorized = true;
      name = Users[i].name;
      break;  // No need to look a the rest
    }
  }
  
  
  // Sound the buzzer when a card is read
  tone(buzzer, 2000); 
  delay(300);        
  noTone(buzzer);
  
  
  delay(500);

  if(authorized){

   nametocard = name;
   led.setPixelColor(0, 255, 0, 0);
   led.show();
   truckCount();
  }
  else{
    Serial.println("Card Not Linked");
    delay(100);

    led.setPixelColor(0, 0, 255, 0);
    led.show();  
    tone(buzzer, 1000); 
    delay(100);        
    noTone(buzzer);
    led.setPixelColor(0, 0, 0, 0);
    led.show();  
    delay(100);

    led.setPixelColor(0, 0, 255, 0);
    led.show();  
    tone(buzzer, 1000); 
    delay(100);        
    noTone(buzzer);
    led.setPixelColor(0, 0, 0, 0);
    led.show();  
    delay(100);

    led.setPixelColor(0, 0, 255, 0);
    led.show();  
    tone(buzzer, 1000); 
    delay(100);        
    noTone(buzzer);
    led.setPixelColor(0, 0, 0, 0);
    led.show();  
    delay(100);

    return;
  }  
}

/////////////////////////////////////////////////////////////////////Truck Count/////////////////////////////////////////////////////////////////////

void truckCount(){

  logCard();
}

/////////////////////////////////////////////////////////////////////Log RFID Card/////////////////////////////////////////////////////////////////////

void logCard() {
  // Enables SD card chip select pin
  digitalWrite(CS_SD,LOW);
  
  // Open file
  
  myFile=SD.open(filename, FILE_WRITE);

  if (myFile) {
    DateTime now = rtc.now();
    
    Serial.println("Saving Data.....");
  

    sprintf(dateandtime, "%04d/%02d/%02d,%02d:%02d", now.year(), now.month(), now.day(), now.hour(),now.minute()); //compiles date and time yyyy/mm/dd,hh:mm
    
    Serial.print("Truck Number: ");
    Serial.println(nametocard);
    Serial.print("Date and Time: ");
    Serial.println(dateandtime);
    
    myFile.print(nametocard);
    myFile.print(",");  
    myFile.println(dateandtime);
        
    myFile.close();
    delay(500);
    led.setPixelColor(0,0,0,0);
    led.show();

  }
  // Disables SD card chip select pin  
  digitalWrite(CS_SD,HIGH);
}

const means constant. So the variable is read only and cannot be written to. You will get a compile time error if you try.

  • means that the variable is a pointer. So instead of being the actual data stored in the variable itself, the variable holds the memory address of where the data is actually stored.

One of the advantages of a pointer is you can update it to point to a completely different string somewhere else in memory. That’s far quicker and easier than copying the whole string to a new location.

Arrays and pointers are closely related in C/C++, and pointers are a very useful programming construct. However you have to be careful with them, it’s very easy to end up writing to memory locations you have no business accessing.

So in this case

struct USER
{
  unsigned long ID;
  const char *name;
} Users[] =
{
  {0x734AD60, "7100"},
  {0xE4429C22, "7101"},
};
const byte UserCount = sizeof Users / sizeof Users[0];

char *nametocard = "";

instead of actually changing the variable "name", it simply points to the location in the memory that this is stored?

If that is correct then char nametocard = "" should be char nametocard = ""...correct? That is a changing variable and should not be just pointed to?

ClncyFshSlayer:
If that is correct then char nametocard = "" should be char nametocard = ""...correct? That is a changing variable and should not be just pointed to?

Those two expressions are identical, as are:

char* nametocard = ""
char*nametocard = ""
char * nametocard = ""
and
char   *   nametocard = ""

ClncyFshSlayer:
If that is correct then char nametocard = "" should be char nametocard = ""...correct? That is a changing variable and should not be just pointed to?

Not sure what you are asking, sorry. All of these are syntactically equivalent...

char *nametocard = "";
char* nametocard = "";
char * nametocard = "";
char*nametocard = "";

1 and 2 are very common, and which people use is entirely down to personal coding style. Personally I think the pointer indicator (*) belongs with the type (char) and so prefer 2.
Using examples 3 and 4 would probably cause people to look at you funny, but the compiler won’t care.

const and pointers are two totally separate concepts. You can code “const int X = 10;” if you want a constant X of value 10.

Modifiable pointer to a variable char

char* ptr

Modifiable pointer to a constant char

const char* ptr

Constant pointer to a variable char

char* const ptr

Constant pointer to a constant char

const char* const ptr