0

I'm trying to construct and return a string in C, but running into a function returns address of local variable [-Wreturn-local-addr] compiler warning. I get that returning packet like I'm trying to do won't work, because packet is a pointer to the beginning of my chars of size packet_size, and that memory address isn't valid outside my function. I'm running on an AVR chip and don't want to use malloc. How should I go about solving this problem?

#include <stdio.h>
#include <string.h>
#include <stdint.h>

const char* construct_packet(const char* data);
void append(char* str, char c);

int main()
{
    const char* my_packet = construct_packet("QERT");
    printf("%s", my_packet);

    return 0;
}

const char* construct_packet(const char* data)
{
    const char training_chars[] = "___";
    const char start_char = '>';
    uint8_t checksum = 0;
    for(uint16_t i = 0; i < strlen(data); i++) {
        checksum += data[i];
    }
    const char checksum_char = checksum;

    uint8_t packet_size = strlen(training_chars) + strlen(data) + 2; // Plus 2 for start byte and checksum byte
    char packet[packet_size];

    strcat(packet, training_chars);
    append(packet, start_char);
    strcat(packet, data);
    append(packet, checksum_char);

    return packet;
}

void append(char* str, char c)
{
    str[strlen(str) + 1] = c;
}
kibowki
  • 4,206
  • 16
  • 48
  • 74
  • This is very dirty, and I abhor the thought of doing this, but could a `static char*` variable work for you if there nothing else you can do? – Nik Oct 31 '17 at 02:08
  • @jonathon-reinhart OP can't use malloc your duplicate is wrong. or maybe not this [answer](https://stackoverflow.com/a/22288966/7076153) work for this question. You right my bad. – Stargateur Oct 31 '17 at 03:42
  • @Stargateur Read the entire first answer. – Jonathon Reinhart Oct 31 '17 at 03:44

2 Answers2

1

If you don't want to use dynamic memory allocation, and don't want to use a static buffer, then you might try calculating and providing the memory buffer on the stack:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

const char* construct_packet(const char* data, const char* training_chars, const char start_char, char* packet);
void append(char* str, char c);

int main()
{
    const char data[] = "QERT";
    const char training_chars[] = "___";
    const char start_char = '>';
    const uint8_t packet_size = strlen(training_chars) + strlen(data) + 2; // Plus 2 for start byte and checksum byte
    char packet[packet_size];

    const char* my_packet = construct_packet(data, training_chars, start_char, packet);
    printf("%s", my_packet);  // same as printf("%s", packet);

    return 0;
}

const char* construct_packet(const char* data, const char* training_chars, const char start_char, char* packet)
{
    uint8_t checksum = 0;
    for(uint16_t i = 0; i < strlen(data); i++) {
        checksum += data[i];
    }
    const char checksum_char = checksum;

    strcat(packet, training_chars);
    append(packet, start_char);
    strcat(packet, data);
    append(packet, checksum_char);

    return packet;
}

void append(char* str, char c)
{
    str[strlen(str) + 1] = c;
}
Phil Brubaker
  • 1,257
  • 3
  • 11
  • 14
0

Phil Brubaker: If you don't want to use dynamic memory allocation, and don't want to use a static buffer, then you might try calculating and providing the memory buffer on the stack:

I will not say better, my implementation:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

// in some header file
const char *construct_packet(char *packet, const char* data);
size_t size_packet(const char* data);

int main(void)
{
    const char *data = "QERT";
    size_t packet_size = size_packet(data);
    char packet[packet_size];
    construct_packet(packet, data);
    printf("%s", packet);
}

// can be on a other file of course `training_chars` and `start_char` could be give in parameter
// of course cause there are static `size_packet()` and `contruct_packet()` must be in the same file
static const char * const training_chars = "___";
static const char start_char = '>';

size_t size_packet(const char* data)
{
    // you forgot nul terminate byte
    return sizeof training_chars - 1 + 1 + strlen(data) + 1 + 1;
}

const char *construct_packet(char *packet, const char* data)
{
    size_t i = 0;

    // I replace strcat because I supose you want speed note they are better method that this one
    for (size_t j = 0; training_chars[j] != '\0'; j++) {
        packet[i++] = training_chars[j];
    }

    packet[i++] = start_char;

    // maybe this should be a char but you don't give information about checksum so I can't be sure
    uint8_t checksum = 0;
    for (size_t j = 0; data[j] != '\0'; j++) {
        packet[i++] = data[j];
        checksum += data[j];
    }
    packet[i++] = (char)checksum;

    // you forgot nul terminate byte
    packet[i] = '\0';

    return packet;
}

Of course, you could just not calculate the size and give a maximum:

char packet[256];
construct_packet(packet, data, 256);
Stargateur
  • 24,473
  • 8
  • 65
  • 91