do i need null terminator

I think i might be doing this wrong but i want to know for sure. below I create a char array[] then add an ip address to it,

  char T1_IP[16];
  char T2_IP[16];
  char T3_IP[16];
  char T4_IP[16];
  char TM1_IP[16];
  char TM2_IP[16];
//////////////////////////////////////////////
void recvPacket() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    int len = Udp.read(incomingPacket, 3000);
    char verifyStart[7]; 
    char verifyEnd[7]; 
    //char _data[5];
    strncpy (verifyStart, (char*)incomingPacket, 6 );//6 bytes
    strncpy (verifyEnd, (char *)incomingPacket + len - 6 , 6 );//6 bytes
    verifyStart[6] = '\0'; //null terminate
    verifyEnd[6] = '\0'; //null terminate
  if (strcmp(verifyStart, "T1PAIR") == 0 && strcmp(verifyEnd, "1TAPVU") == 0) {
      char new_ip[15];
      Udp.remoteIP().toString().toCharArray(new_ip, 15);
      if (strcmp(_EEPROM.T1_IP, new_ip) != 0) {
        Udp.remoteIP().toString().toCharArray(_EEPROM.T1_IP, 15);
        if (debugPairing) {
          Serial.println("T1 Paired!");
          Serial.println(_EEPROM.T1_IP);
        }
        _writeEEPROM();
      } else {
        if (debugPairing) {
          Serial.println("No need to update temp 1  address");
        }
      }
    }

in the if statement below the char arrays[] you can see how i convert string to array but i dont add a null terminator. is this okay? .tochararray .toString dont mention terminating the string but i think say expect a terminator? will my code above cause issues?

As far as I know, all of the string routines expect a null terminator. It would be silly to leave them out.

Who knows what will happen if you (in-advisedly) mix Strings with C-strings?

in the if statement below the char arrays[]

All the if statements are below char arrays

jremington:
As far as I know, all of the string routines expect a null terminator. It would be silly to leave them out.

Who knows what will happen if you (in-advisedly) mix Strings with C-strings?

well im having weird issues. such as a serial print statement garbled. im trying to find the error in my code and this part to me stands out the most. Please explain what will happen if i mix c string with Strings. the program worked well until memory usage was a concern. now it seems like i'm having overflows.

Also if udp.remoteIP() returns 4 bytes. would i only need to initialize the array with 5 bytes? does it makes sense to use array[16]?

what will happen if i mix c string with Strings

Garbled Serial.print() results, for one. Program crashes, for another.

jremington:
Garbled Serial.print() results, for one. Program crashes, for another.

could you please be a bit more specific. what part of the code are you talking about?

Can we be clear - are you trying to make an IP address , or a printable representation of an IP address?

TheMemberFormerlyKnownAsAWOL:
Can we be clear - are you trying to make an IP address , or a printable representation of an IP address?

I made a discovery method to find my modules on the network. i send udp messages to every address by looping through the last octet start at 1 ending at 255.

discovery method send messages,

void pairMe() {
  if (WiFi.status() == WL_CONNECTED) {
    if (millis() - pairMarker >= 250) {
      IPAddress myaddress = WiFi.localIP();
      myaddress[3] = 1;
      pairCounter++;
      myaddress[3] = pairCounter;
      Udp.beginPacket(myaddress, 4220);
      Udp.write("PAIRMEEMRIAP");
      Udp.endPacket();
      if (pairCounter >= 255) {
        pairCounter = 0;
      }
      pairMarker = millis();
    }
  }
}

A client will receive a message and attempt to store the IPAddress in the eeprom so that it can be used with Udp.BeginPacket(_EEPROM.IPADDRESS, PORT);.

the client receives the discovery message,

struct {
  char masterIP[15];
} _EEPROM;
String masterIP = "";

void recPacket() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    int len = Udp.read(incomingPacket, 2000);
    char verifyStart[7];
    char verifyEnd[7];
    unsigned long _data;
    strncpy (verifyStart, (char*)incomingPacket, 6);
    strncpy (verifyEnd, (char *)incomingPacket + len - 6 , 6 );
    memcpy(&_data, incomingPacket + 6 , 4);
    verifyStart[6] = '\0'; //null terminate
    verifyEnd[6] = '\0'; //null terminate
    if (strcmp(verifyStart, "PAIRME") == 0) {
      if (strcmp(verifyEnd, "EMRIAP") == 0) {
        String str = Udp.remoteIP().toString();
        char new_ip[15];
        str.toCharArray(new_ip, 15);
        masterIP = Udp.remoteIP().toString();
        if (strcmp(_EEPROM.masterIP, new_ip) != 0) {
          masterIP.toCharArray(_EEPROM.masterIP, 15);
          Serial.println("t4  updated gateway ip");
          _writeEEPROM();
        } else {
          Serial.println("no need to update master ip");
          Serial.println(WiFi.localIP());
        }
        Udp.beginPacket(_EEPROM.masterIP, 4210);
        Udp.write("T4PAIR");
        Udp.write("4TAPVU");
        Udp.endPacket();
        //   }
      }
    }
  }
}

So i am trying to create an Ipaddress that can be handed over to Udp.beginPacket() and be saved in the eeprom. I rely on Udp.remoteIp() to retrieve the address from the senders to be stored in the EEPROM.

Would this make more sense to create an IPAddress object and populate it with udp.remoteip()? thne i can use sprintf to send it to "char _EEPROM.masert_ip[15];?? char array[] is a string? not a String?

          IPAddress ip = Udp.remoteIP();
          sprintf(_EEPROM.masterIP, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);

Wow you guys are such a great help! keep up the good work. not..

notsolowki:
Wow you guys are such a great help! keep up the good work. not..

Waiting to see if that evokes any positive responses.

Why are you storing a character array of the IP address in EEPROM instead of the 4 bytes?

Where in your program do you require the character array representation of the address instead of the 4 bytes of the address?

cattledog:
Why are you storing a character array of the IP address in EEPROM instead of the 4 bytes?

Where in your program do you require the character array representation of the address instead of the 4 bytes of the address?

i think udp.beginPacket(); it would only accept a String or char array or ipaddress object

Instead of all the String and char array conversion, you may find it easier to work with the IP address object and write the four bytes ip[0], ip[1], ip[2], ip[3] into four bytes of the eeprom.
You do not store the address object, just the underlying bytes,

You can certainly recreate the ip address object from the four bytes when you read them.

cattledog:
Instead of all the String and char array conversion, you may find it easier to work with the IP address object and write the four bytes ip[0], ip[1], ip[2], ip[3] into four bytes of the eeprom.
You do not store the address object, just the underlying bytes,

You can certainly recreate the ip address object from the four bytes when you read them.

i didnt think about that. sprintf() should be okay right?

IPAddress ip = Udp.remoteIP();
sprintf(_EEPROM.masterIP, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);

You are still creating a character array from the bytes. You don't need to do that. It is making things more complex.

This was discussed back in one of your previous threads.
https://forum.arduino.cc/index.php?topic=705847.msg4743247#msg4743247

You were using the 4 bytes correctly in reply #7, but then you went back to storing the character array.

@juraj had the right advice in reply #13

you can store the IP address in EEPROM. the 4 bytes. then read it into a variable in memory and use that variable in beginPacket

cattledog:
You are still creating a character array from the bytes. You don't need to do that. It is making things more complex.

This was discussed back in one of your previous threads.
save remoteIP() as ipaddress - #3 by notsolowki - Programming Questions - Arduino Forum

You were using the 4 bytes correctly in reply #7, but then you went back to storing the character array.

@juraj had the right advice in reply #13

i dont know how to store the 4 bytes. the only way i can thing of is a char array for each byte and then save the eeprom. i store the whole struct in eeprom dont know how to store a single byte like you describe,

struct {
  char UV_IP[20];
  char T1_IP[20];
  char T2_IP[20];
  char T3_IP[20]; //WATER TEMP
  char T4_IP[20];
  char TM1_IP[20]; //TIMER MODULE 1
  char TM2_IP[20];
  char C021_IP[20];
  char WM1_IP[20];
  char PHM1_IP[20];
  char sta_ssid[15];
  char sta_password[15];    
  char system_password[15];
} _EEPROM;

void _writeEEPROM () {
  EEPROM.put(addr, _EEPROM);
  EEPROM.commit();    //Store data to EEPROM
  Serial.println("-------------eeprom write!");
}

    if (strcmp(verifyStart, "UVPAIR") == 0 && strcmp(verifyEnd, "RIAPVU") == 0) {
      char new_ip[20];
      new_ip[19] = '\0';
      IPAddress sender_ip = Udp.remoteIP();
      sprintf(new_ip, "%d.%d.%d.%d", sender_ip[0], sender_ip[1], sender_ip[2], sender_ip[3]);
      if (strcmp(_EEPROM.UV_IP, new_ip) != 0) {
        sprintf(_EEPROM.UV_IP, "%d.%d.%d.%d", sender_ip[0], sender_ip[1], sender_ip[2], sender_ip[3]);
        _EEPROM.UV_IP[19] = '\0';
        if (debugPairing) {
          Serial.println("UV Paired!");
          Serial.println(_EEPROM.UV_IP);
        }
        _writeEEPROM();
      } else {
        if (debugPairing) {
          Serial.println("no need to update uv address");
        }
      }
    }

notsolowki:
Wow you guys are such a great help! keep up the good work. not..

I have a chronic, eventually terminal, sexually-transmitted condition called "a life".

It involves sleeping.

I'll be doing a lot more of it when I see your name at the top of a topic.

What you now have with the sprintf() to form the character array is a big improvement over when you were using

Udp.remoteIP().toString().toCharArray();

The sprintf() method looks like it will work if you want to stick with the character array representation of the ip address.

If you want to use the 4 bytes instead, I think the following code will do it. memcmp() replaces strcmp() and the 4 bytes replace the 20 chars.

struct {
  //char UV_IP[20];
  byte UV_IP[4];
  char T1_IP[20];
  char T2_IP[20];
  char T3_IP[20]; //WATER TEMP
  char T4_IP[20];
  char TM1_IP[20]; //TIMER MODULE 1
  char TM2_IP[20];
  char C021_IP[20];
  char WM1_IP[20];
  char PHM1_IP[20];
  char sta_ssid[15];
  char sta_password[15];
  char system_password[15];
} _EEPROM;

void _writeEEPROM () {
  EEPROM.put(addr, _EEPROM);
  EEPROM.commit();    //Store data to EEPROM
  Serial.println("-------------eeprom write!");
}

if (strcmp(verifyStart, "UVPAIR") == 0 && strcmp(verifyEnd, "RIAPVU") == 0) {
  //char new_ip[20];
  //new_ip[19] = '\0';
  IPAddress sender_ip = Udp.remoteIP();
  //sprintf(new_ip, "%d.%d.%d.%d", sender_ip[0], sender_ip[1], sender_ip[2], sender_ip[3]);
  //if (strcmp(_EEPROM.UV_IP, new_ip) != 0) {
  if (memcmp(EEPROM.UV_IP, sender_ip, 4) != 0) {
    //sprintf(_EEPROM.UV_IP, "%d.%d.%d.%d", sender_ip[0], sender_ip[1], sender_ip[2], sender_ip[3]);
    //_EEPROM.UV_IP[19] = '\0';
    for (byte j = 0; j < 4; j++)
    {
      _EEPROM.UV_IP[j] = sender_ip[j];
    }

    if (debugPairing) {
      Serial.println("UV Paired!");
      for (byte j = 0; j < 4; j++)
      {
        Serial.write(_EEPROM.UV_IP[j]);
        Serial.println();
      }
    }
    _writeEEPROM();
  } else {
    if (debugPairing) {
      Serial.println("no need to update uv address");
    }
  }
}

My esp8266 is crashing and i have not been able to figure out why. this is my decoded stack trace,

Exception 0: Illegal instruction
PC: 0x465569cf
EXCVADDR: 0x00000000

Decoding stack results
0x40100eaf: free(void*) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_malloc.cpp line 398
0x40101142: calloc(size_t, size_t) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_malloc.cpp line 908
0x402299d2: new_linkoutput at glue-lwip/lwip-git.c line 260
0x40229df0: ethernet_output at netif/ethernet.c line 312
0x4023182d: etharp_output_LWIP2 at core/ipv4/etharp.c line 896
0x402330fc: ip4_output_if_opt_src at core/ipv4/ip4.c line 1764
0x40100ee4: malloc(size_t) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_malloc.cpp line 552
0x40233bf0: mem_malloc at core/mem.c line 210
0x40233144: ip4_output_if_opt at core/ipv4/ip4.c line 1577
0x40231a85: igmp_send at core/ipv4/igmp.c line 797
0x40100ee4: malloc(size_t) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_malloc.cpp line 552
0x40100c2b: umm_free_core(void*) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_malloc.cpp line 351
0x40231e2c: igmp_tmr at core/ipv4/igmp.c line 658
0x4022af50: lwip_cyclic_timer at core/timeouts.c line 233
0x4022af60: lwip_cyclic_timer at core/timeouts.c line 243
0x40229ea9: memp_free at core/memp.c line 447
0x4022b0f8: sys_check_timeouts at core/timeouts.c line 390
0x4021dd80: loop_task(ETSEvent*) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 205
0x4021b7a0: _GLOBAL__sub_D__ZN14HardwareSerialC2Ei() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/HardwareSerial.h line 72
0x4021c9e8: _GLOBAL__sub_D__ZN12UpdaterClassC2Ev() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\Updater.cpp line 579
0x4021dc14: _GLOBAL__sub_D__ZN6StringC2EPKc() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\WString.cpp line 856
0x40229745: glue2esp_linkoutput at glue-esp/lwip-esp.c line 301
0x40100ee4: malloc(size_t) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_malloc.cpp line 552
0x402299d2: new_linkoutput at glue-lwip/lwip-git.c line 260
0x40229df0: ethernet_output at netif/ethernet.c line 312
0x402312a4: etharp_raw at core/ipv4/etharp.c line 1165
0x40231ac6: igmp_delaying_member at core/ipv4/igmp.c line 698
0x4023149a: etharp_request at core/ipv4/etharp.c line 1202
0x40231b23: igmp_report_groups at core/ipv4/igmp.c line 205
0x4010039c: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 177
0x40214ed0: Adafruit_GFX::drawChar(short, short, unsigned char, unsigned short, unsigned short, unsigned char, unsigned char) at C:\Users\Laptop\Documents\Arduino\libraries\Adafruit_GFX_Library\Adafruit_GFX.cpp line 1105
0x4010039c: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 177
0x40229bc5: esp2glue_netif_set_up1down0 at glue-lwip/lwip-git.c line 485
0x4010039c: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 177
0x4022dbd8: netif_set_addr_LWIP2 at core/netif.c line 717
0x4010039c: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 177
0x4010039c: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 177
0x4010039c: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 177
0x4010039c: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 177
0x4020faed: esp8266webserver::ESP8266WebServerTemplate ::handleClient() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\libraries\ESP8266WebServer\src/ESP8266WebServer-impl.h line 312
0x4020faed: esp8266webserver::ESP8266WebServerTemplate ::handleClient() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\libraries\ESP8266WebServer\src/ESP8266WebServer-impl.h line 312
0x40100720: millis() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_wiring.cpp line 188
0x4020fbec: pairMe() at C:\Users\Laptop\Documents\Arduino\esp_scan_master/esp_scan_master.ino line 184
0x40210ff0: ESP8266WiFiSTAClass::status() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\libraries\ESP8266WiFi\src\ESP8266WiFiSTA.cpp line 634
0x4020fd3e: loop() at C:\Users\Laptop\Documents\Arduino\esp_scan_master/esp_scan_master.ino line 163
0x40220130: std::_Function_base::_Base_manager ::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation) at c:\users\laptop\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\2.5.0-4-b40a506\xtensa-lx106-elf\include\c++\4.8.2/functional line 1934
0x4022011c: std::_Function_handler ::_M_invoke(std::_Any_data const&) at c:\users\laptop\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\2.5.0-4-b40a506\xtensa-lx106-elf\include\c++\4.8.2/functional line 2069
0x4010039c: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 177
0x401003bd: esp_schedule() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 125
0x4021df2d: loop_wrapper() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 199

also the crashes happen without processing incoming packets.