Go Down

Topic: Learning about strcpy (Read 14767 times) previous topic - next topic

SouthernAtHeart

I saw some code that had this neat function, and I'm wondering if it is possible and/or if it would benefit me here in this example.  Would it make my code smaller/neater to somehow use the strcpy() function here.  I'm not sure what I need to eliminate though.  Currently, I loop thru the string characters and copy them 1 by 1. (around line 12 in this sample)
Code: [Select]
void next3Files() { //opens the next file on the SD card
  for (int a = 0; a < 3; a++) { //loop thru 3 files
    File entry =  dir.openNextFile();
    if (! entry) { //there isn't a next file
      entry.close(); //close the entry
      dir.rewindDirectory(); //rewind
      entry =  dir.openNextFile(); //get the first file
    }
    entryName = entry.name();
    entry.close();
    int  len = strlen(entryName); //how long is the name?
    memset(names[a], 0, sizeof(names[a])); //delete the previous value. Is this necessary?
    for (int i = 0; i < len; i++) {
      names[a][i] = entryName[i];

    }
  }
}


Then, when I print the 3 names to the LCD display I use this code.  Is there a way to just print the name, without having to loop thru each character, or is what I'm doing the best way? (About line 12 and 13)
Code: [Select]
void Select_Part() {
  do { //keep looping through names until they select one
    next3Files(); //get the next 3 file names
    disp.lcd_cls(); //clear display
    for (int a = 0; a < 3; a++) { //loop thru 3 names
      int  len = strlen(names[a]); //how long is the name?
      disp.lcd_rowcol(a, 0); //row, col
      disp.lcd_print(a + 1); //the selection number
      disp.lcd_print(F(": ")); //the selection number suffix
      DEBUG_PRINT(a + 1); //the selection number
      DEBUG_PRINT(": ");  //the selection number suffix
      for (int i = 0; i < len - 4; i++) {
        disp.lcd_print(names[a][i]); //the filename
        DEBUG_PRINT(names[a][i]); //the filename
      }
      DEBUG_PRINTLN();
    }
    disp.lcd_print("4. MORE  5. CANCEL"); //4 OR 5 TO SEE MORE FILE NAMES OF CANCEL
    DEBUG_PRINTLN("4. MORE  5. CANCEL"); //4 OR 5 TO SEE MORE FILE NAMES OF CANCEL
    DEBUG_PRINTLN();
    while (1) { //wait for key input
      byte k = checkKeyBuffer(); //get a keypress from the user
      switch (k) {
        case 1:
          drillHole(names[0], 1); //drill selection 1
          return; //after drilling the part, we'll return to main menu
        case 2:
          drillHole(names[1], 1); //drill selection 2
          return; //after drilling the part, we'll return to main menu
        case 3:
          drillHole(names[2], 1); //drill selection 3
          return; //after drilling the part, we'll return to main menu
        case 4:
          //show the next 3 files
          break; //exit the key input loop to show the next 3 entries
        case 5: //cancel
          return;
        case keyTimeout: //user input timed out
          return;
      }
    }
  }
  while (1); //until break
}

sterretje

#1
Aug 17, 2016, 07:46 pm Last Edit: Aug 17, 2016, 07:48 pm by sterretje
Without knowing what 'disp' exactly is, it's difficult to answer your second question. With the 'normal' LCD, you can simply print the string
Code: [Select]
// print name on lcd
lcd.print(names[a]);
// go to next line on lcd
lcd.setCursor(n,0);


For the first question, you're not copying the terminating nul character. So the answer to your comment 'is this necessary' is yes. If you use strcpy(), you don't need the strlen(), memset() and don't need the loop.
Code: [Select]
strcpy(names[a], entryName);


Note:
not tested.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

SouthernAtHeart

Oh, thanks. That's even simpler than I imagined!

MorganS

Get used to using the length-limited versions of those functions. strncpy() should always be your default and only use strcpy() in an emergency.

Lazily using strcpy() has cost the computer industry billions with viruses taking advantage of the possibilities of overflow. Your Arduino can't catch a virus but it will save you lots of hours debugging a seemingly-random fault because one function wrote past the end of its assigned buffer.
"The problem is in the code you didn't post."

SouthernAtHeart

Get used to using the length-limited versions of those functions. strncpy() should always be your default and only use strcpy() in an emergency.

Lazily using strcpy() has cost the computer industry billions with viruses taking advantage of the possibilities of overflow. Your Arduino can't catch a virus but it will save you lots of hours debugging a seemingly-random fault because one function wrote past the end of its assigned buffer.
So I just used this?
strncpy(names[a], entryName)

J-M-L

I disagree although all points of view are OK. I would say don't use strncpy() by default, it will get you in trouble or adds un-necessary bound checks if you know what you are doing or if you don't it will sometimes leave you with a string that is not properly terminated by a '\0'

You need to use strncpy only when it is useful, not as a replacement for not overflowing your char array.

There are strlcpy() and strlcat() functions to copy and concatenate strings respectively that  are designed to be safer, more consistent, and less error prone replacements for strncpy() and strncat(). They add a bit of error checking cost all the time that is safe but unecessary if you know want you do...

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

PaulMurrayCbr

So I just used this?
strncpy(names[a], entryName)
No. Rather than telling you what to use, I will point you at the documentation: http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

SouthernAtHeart

In my application, the string I'm copying, a filename from an SD card, will always be a maximum of 8 characters plus the extension, so 12 characters. And the names[a] variable is defined as 13 characters, so I won't have to worry about the string being too big.  I do have a tight budget on sketch size, so is the best and most memory saving way for me to use this one?
strcpy(names[a], entryName);

econjack

...is the best and most memory saving way for me to use this one?
strcpy(names[a], entryName);
You're going to find that the best way to answer your question is to write a simple test and find out:

Code: [Select]

void setup() {
  char input[] = "When in the course of human events...";
  char temp[40];
  int length;
  
  Serial.begin(9600);
  
  length = strlen(input);
  Serial.print("Input length is: ");
  Serial.println(length);

  strcpy(temp, input);              // flash: 2366, SRAM: 254, works
//  strncpy(temp, input, length);   // ??
//  memcpy(temp, input, length);    // ??
//  memmove(temp, input, length);   // ??
  
  Serial.println(temp);
}

void loop() {

}

You'll also find you tend to remember experiments you write and test more than if someone tells you the answer.

Go Up