Memory Leak reading file line by line? (solved)

I am a bit of a noob as far as Arduino and C(++) goes. but I am having to manually clear a char buf[] even when reinitializing it in a new scope? I would like to understand why and potentially remove my reset_buf() function in my code.

the output WITHOUT reset_buf():

HELLO SDCARD
SD OK!
LOOP
Open test.asc
INP Hello Arduino
CMD: INP
SKP RETURNArduino
CMD: SKP
SLP 1000RNArduino
CMD: SLP
INP Bye Arduinono
CMD: INP
SKP RETURNduinono
CMD: SKP

and then the output WITH reset_buf():

HELLO SDCARD
SD OK!
LOOP
Open test.asc
INP Hello Arduino
CMD: INP
SKP RETURN
CMD: SKP
SLP 1000
CMD: SLP
INP Bye Arduino
CMD: INP
SKP RETURN
CMD: SKP

Hope someone can help and explain.

Here is my code, i have to reset_buf in the loop():

#include <SPI.h>
#include <SD.h>

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  while(!Serial);
  Serial.println("HELLO SDCARD");
  if (!SD.begin(10)) {
    Serial.println("SD ERROR");
    while (1);
  }
  Serial.println("SD OK!");
}

// Read to \n or max 1024 bytes
void readLine(char buf[], File f) {
  int rl_len = 0;
  while (f.available() && rl_len < 1024) {
    char c = f.read();
    if (c == '\n') break;
    buf[rl_len] = c;
    rl_len++;
  }
}

void reset_buf(char buf[]) {
  for (int i = 0; i < 1024; i++) {
    buf[i] = (char)0;
  }
}

void processLine(char line[]) {
  Serial.println(line);
  char cmd[3];
  for (int li = 0; li < 3; li++) {
    cmd[li] = line[li];
  }
  Serial.print("CMD: ");
  Serial.println(cmd);
}

void loop() {
  Serial.println("LOOP");
  File script = SD.open("test.asc");
  Serial.println("Open test.asc");

  while(script.available()) {
    char buf[1024];
    readLine(buf, script);
    processLine(buf);
    reset_buf(buf);
  }
  script.close();
  SD.end();

  while(1); // freeze device
}

You do not have to clear the input buffer to reuse it.

However, to use lines like Serial.println(cmd); to print from character array, the array must be a valid "C-string", that is, consisting of printable characters and have a terminating zero byte. I don't see any place in your code where you are adding that terminating zero.

The variable cmd, as declared by char cmd[3] can store only two ASCII characters, plus the terminating zero byte.

For 3 characters, try

  char cmd[4];
  for (int li = 0; li < 3; li++) {
    cmd[li] = line[li];
  }
  cmd[3]=0;  //terminate the C-string

Making sure not to go beyond the end of the array, it costs very little to make the array always a valid C string as you build it:

  while (f.available() && rl_len < 1024) {
    char c = f.read();
    if (c == '\n') break;
    buf[rl_len] = c;
    rl_len++;
    buf[rl_len] = '\0';
  }

Dunno about this exact case, but when you are building over multiple trips through the loop(), one reason to terminate as you go is that the character array is always something you could print, for example, to see what's there so far.

a7

Thanks for the reply, I didn't know we HAD to add a \0 to terminate a string. I thought if it was the right size it'd be fine, still not sure why that isn't the case though.

Thanks for the help that's a really nice easy way to make sure the last char is always \0.

When Serial.print() is called to print a C-string, it first determines the length of that string by searching memory for the terminating zero, and attempts to print that many bytes.

That zero could be anywhere in the memory following an improperly terminated string, leading to memory access violations.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.