I am having a structure:
struct K
{
char a[10];
char b[10];
};
I wish to convert this structure to a char* pointer and print the value on Uart. Uart takes char* pointer as input.
My main function looks like:
void main()
{
struct K x= { "Hello","Pollo"};
struct K *revert;
char *buffer;
buffer = (char *)&x;
revert = (struct K *) buffer;
printf("%s %s", revert->a,revert->b);
}
Note: printf() won't work, I am using a UART.
I want to print the buffer value on UART when it is done with converting structure pointer to char * pointer. Is it possible to do that?
Another approach to splitting and recombining the struct elements into a char* string is with the string functions sprintf and then strncpy. There are many, many ways to do this. Simple pointer arithmetic will do, etc.. But this approach is fairly clean and straightforward:
#include <stdio.h>
#include <string.h>
struct K
{
char a[10];
char b[10];
};
int main (void)
{
char tmp[21] = {0};
char *buf = tmp;
struct K x = { "Hello","Pollo"};
struct K rev = {{0},{0}};
/* combine x.a & x.b into single string in buf */
sprintf (buf, "%s%s", x.a, x.b);
/* print the combined results */
printf ("\n combined strings: %s\n\n", buf);
/* get original lenght of x.a & x.b */
size_t alen = strlen(x.a);
size_t blen = strlen(x.b);
/* copy from buf into rev.a & rev.b as required */
strncpy (rev.a, buf, alen);
strncpy (rev.b, buf+alen, blen);
printf (" recombined: rev.a: %s rev.b: %s\n\n", rev.a, rev.b);
return 0;
}
Output
$ ./bin/struct2str
combined strings: HelloPollo
recombined: rev.a: Hello rev.b: Pollo
Related
If I have a code:
typedef struct s_ {
int a;
char* b;
} s;
int main()
{
s* st = malloc(sizeof(s));
st->b = malloc(20*sizeof(char));
st->a = 1;
st->b = "foo";
}
Is it possible here to access data in char array using offset?
For example offset here is 4 bytes, I know it and can calculate using for example offsetof() macro, but I can't access data using pointer arithmetics like:
printf("%s", (char*)(st+4));
I would be very happy if someone could help here :)
The answer may be surprising: st+4 actually increments the pointer by 32 bytes!
This is because the type of st is struct s_ * and when you add 4 to that, it is incremented by 4 times the size of the struct.
In order to move by 4 bytes, you need to cast the pointer to char* first and then increment it.
Try this: printf("%s", *(char**)((char*)st + 4));
Edit:
Added *(char**).
It is needed because by incrementing the pointer, we don't get the beginning of the string, we get the address of the pointer to the beginning of the string.
So we need to cast it to the proper type and dereference it.
You can calculate the byte address of the char * element b (which is a char ** value) using (char *)st + offsetof(s, b); therefore you can access the string using code like this:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct s_
{
int a;
char *b;
} s;
int main(void)
{
s *st = malloc(sizeof(s));
st->b = malloc(20 * sizeof(char));
st->a = 1;
strcpy(st->b, "foo");
char *str = *(char **)((char *)st + offsetof(s, b));
printf("[%s]\n", str);
return 0;
}
The output is a line containing [foo].
Now you know why you don't want to have to do this — let the compiler solve it for you:
printf("[%s]\n", st->b);
This question is getting close to Is it possible to dynamically define a struct in C?
If you use printf("%s", (char*)(st+4));,result have been offset 4*struct s
You want to printf the fourth character,could write like this
char *ptr = null;
ptr = st;
printf("[%s]",ptr);
I've the following code, where.
s[] - generates a char array and
longStr - is a cons char*.
I want to combine these 2 into a single const char* such that s should be added first followed by longStr.
something like below:
const char* combinedStr = ADD s[] and then longStr;
The size of longStr can keep changing. Hence, allocating the combinedStr statically wouldn't be a good utilization of memory.
Is there a way to d o it dynamically without allocating the size statically for the combinedStr( also without using VLA).
Code
void concatenate(const char* longStr)
{
time_t t = time(NULL);
struct tm timeinfo;
localtime_s(&timeinfo, &t);
char s[100];
strftime(s, sizeof(s), "%c", &timeinfo);
//NOW I WANT TO Combine "s[]" & longStr in such a way that s should be added 1st followed by longStr.
const char* combinedStr = ADD s[] and then longStr;
}
You could use malloc, strcpy and strcat
Something like:
#include <stdio.h>
#include <time.h>
void concatenate(const char* longStr)
{
time_t t = time(NULL);
struct tm timeinfo;
localtime_r(&t, &timeinfo);
char s[100];
strftime(s, sizeof(s), "%c", &timeinfo);
// Allocate memory and put the string together
const char* p = malloc(strlen(s) + strlen(longStr) + 1); // note: Add 1 for the string termination
strcpy(p, s);
strcat(p, longStr);
printf("%s\n", p);
free(p);
}
int main(void) {
char* p = "Hello world";
concatenate(p);
return 0;
}
strcpy and strcat, as mentioned in 4386427's answer. You have to be careful of buffer overflows (as in that answer).
Other options are sprintf and (if not using too old a compiler) snprintf.
void concatenate(const char* longStr)
{
time_t t = time(NULL);
struct tm timeinfo;
localtime_s(&timeinfo, &t);
char s[100];
strftime(s, sizeof(s), "%c", &timeinfo);
//NOW I WANT TO Combine "s[]" & longStr in such a way that s should be added 1st followed by longStr.
// calculate the size:
// either this:
int buflen = snprintf(NULL, 0, "%s%s",s, longstr) + 1;
// or this:
int buflen = strlen(s) + strlen(longstr) + 1;
// allocate:
const char* combinedStr = malloc(buflen);
// then either this:
snprintf(combinedStr, buflen, "%s%s", s, longstr);
// or this:
sprintf(combinedStr, "%s%s", s, longstr);
// do what you need to with combinedStr
free(combinedStr);
}
Remember to free the memory when you are done with combinedStr. If you pass it out of the function and use it there, then you need to free it outside the function, when you are finished with it.
I want to copy variable length structs to a buffer. My struct looks like this:
typedef struct{
int flag;
int size;
unsigned char name[0];
} sp;
I do not know the size of name in advance. After I get size I malloc this struct by:
sp *s = malloc(sizeof(sp)+size)
To copy to a buffer, I do this:
char *buf = calloc(1000, sizeof(*buf));
memcpy(buf, s, sizeof(sp)); //s is of type sp with all memebers initialized
My buffer remains empty. What am I doing wrong?
I don't think you want to declare name as array of pointers, but instead an array of chars.
typedef struct {
int flag;
int size;
char name[];
} sp;
Then you can create an instance like this.
int size = 10;
sp *s = malloc(sizeof(sp)+size);
s->flag = 0;
s->size = size;
strncpy(s->name, "Hello!", size);
s->name[size - 1] = '\0'; // Make sure name is NULL-terminated
You can copy the structure into a buffer as follows.
void *buf = calloc(1000, 1);
memcpy(buf, s, sizeof(s)+ s->size);
Print out the names as follows to check it worked.
printf("Name is %s.\n", s->name);
printf("The buffer's copy of name is %s.\n", ((sp*)buf)->name);
Using pure C (and the C-preprocessor) I would like to create a string buffer that includes a length parameter, so that I could pass it around easily and any functions that operate on it could do so without danger of writing past the end. This is simple enough:
typedef struct strbuf_t_ {
int length;
char str[1];
} strbuf_t;
but then if I want a small scratch space on the stack to format some output text, there is no trivial way to allocate a strbuf_t on the stack. What I would like is some clever macro that allows me to do:
STRBUF(10) foo;
printf("foo.length = %d\n", foo.length); // outputs: foo.length = 10
strncpy(foo.str, "this is too long", foo.length);
Unfortunately I don't seem to be able to do that. The best I've come up with is:
#define STRBUF(size, name) \
struct {\
strbuf_t buf;\
char space[size - 1];\
char zero;\
} name ## _plus_space_ = { .buf={.length=size}, .space="", .zero='\0'};\
strbuf_t *name = &name ## _plus_space_.buf
int main(void)
{
STRBUF(10, a);
strncpy(a->str, "Hello, world!", a->length);
printf("a->length = %d\n", a->length); // outputs: a->length = 10
puts(a->str); // outputs: Hello, wor
}
This meets all of the requirements I listed, but a is a pointer not the structure itself, and the allocation is certainly not intuitive.
Has anyone come up with something better?
I think you are already pretty close to a solution. Just keep a char* in your struct and allocate it via char-array. In order to have the save trailing zero at the end of string, just allocate an extra char additional to the size and initialize the whole array with zeroes.
typedef struct
{
int length;
char* str;
} strbuf_t;
#define STRBUF(varname, size) \
char _buffer_ ## varname[size + 1] = {'\0'}; \
strbuf_t varname = { size, _buffer_ ## varname }
int main()
{
STRBUF(a, 10);
strncpy(a.str, "Hello, world!", a.length);
printf("a.length = %d\n", a.length);
puts(a.str);
}
Perhaps the following. Allocate the memory with an aligned VLA and then overlay.
typedef struct strbuf_t_ {
int length;
char str[];
} strbuf_t;
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdalign.h>
int main(void) {
char *s = "Hello";
size_t length = strlen(s);
size_t n = sizeof (strbuf_t) + length + 1;
_Alignas(strbuf_t) unsigned char mem[n];
strbuf_t *xx = (strbuf_t*) mem;
xx->length = length;
memcpy(xx->str, s, n+1);
printf("int:%zu s:%zu n:%zu mem:%zu\n",
sizeof xx->length, sizeof (strbuf_t), n, sizeof mem);
return 0;
}
Output
int:4 s:4 n:6 mem:10
Note: C99 allows the last struct member to have an indefinite array count of []
This is probably a really stupid question, but
I have an array of structs outside of int main
typedef struct{
char c;
int k;
}factor_t;
and I declared
factor_t *factors = malloc(INIT*sizeof(*factors));
where INIT is 10
After running my function, I have an array of structs each which holds a char, c, and integer, k - e.g., factors[5].c could hold "b" or "d" or "e" and factors[5].k could hold "3" or "33" or "333"
I need to somehow insert these into a string, but I can't seem to
strcat(destination,c or k);
they both give me pointer to integer errors, destination is a char*
How would I go about putting these into a string? I'm aiming to get a string that looks like
ck
ck
ck
that is, a pattern of "ck\n" per struct, where c = char and k = integer
I use strcat(destination, "\n"); for the \n and it works, but I can't do the same with c and k
Calculate the length of the string and output with that offset.
#include <stdio.h>
#include <string.h>
typedef struct{
char c;
int k;
}factor_t;
void struct_cat(char *str, factor_t f) {
sprintf(str + strlen(str), "%c%d", f.c, f.k);
}
int main(void) {
factor_t fac = {'b', 33};
char buf[100] = "hogehoge";
struct_cat(buf, fac);
puts(buf);
return 0;
}
strcat appends a copy of the source string to the destination string. It expects c to be a null terminated string not a single char
If you want to add a single char to an array that is larger than n and the null terminating char is at index n
destination[n] = c;
destination[n+1] = '\0;
you have to be certain that destination is large enough.
If you want to format print additional data to destination string, again make sure destination is large enough and do :
sprintf(destination + n, "%c%d\n", c, k);
Or if you know how that destination has m chars left :
snprintf(destination + n, m, "%c%d\n", c, k);
With this if you attempt to print more than m chars the extra ones will be discarded.
You can use sprintf to do so . -
size_t len=strlen(destination); // calculate before concatenation
sprintf(&destination[len], "%c%d\n", factors[5].c,factors[5].k); // string with newline
destination should be of type char *.
If you need separate this feature use function (like #MikeCAT). But use of snprintf() and strncat() does not allow to go beyond the array bounds:
void strncat_struct(char *buffer, size_t buffer_size, factor_t f)
{
char tmp_buf[32];
snprintf(tmp_buf, sizeof(tmp_buf), "%c, %d\n", f.c, f.k);
strncat(buffer, tmp_buf, buffer_size);
}
int32_t main(int32_t argc, char **argv)
{
//...
char buffer[256] = {0};
for(i = 0; i < INIT; i++) {
strncat_struct(buffer, sizeof(buffer), factors[i]);
}
//...
}
Without using additional function. It is theoretically faster, couse there is no need to calculate string length:
int32_t main(int32_t argc, char **argv)
{
//...
char buffer[256];
char *buf_ptr = buffer;
size_t buf_size = sizeof(buffer);
for(i = 0; i < INIT; i++) {
int32_t printed;
printed = snprintf(buf_ptr, buf_size, "%c, %d\n", factors[i].c, factors[i].k);
buf_ptr += printed;
buf_size -= printed;
}
//...
}