Returning structs - c

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;
}
//...
}

Related

copy a const char* into array of char (facing a bug)

I have following method
static void setName(const char* str, char buf[16])
{
int sz = MIN(strlen(str), 16);
for (int i = 0; i < sz; i++) buf[i] = str[i];
buf[sz] = 0;
}
int main()
{
const char* string1 = "I am getting bug for this long string greater than 16 lenght);
char mbuf[16];
setName(string,mybuf)
// if I use buf in my code it is leading to spurious characters since length is greater than 16 .
Please let me know what is the correct way to code above if the restriction for buf length is 16 in method static void setName(const char* str, char buf[16])
When passing an array as argument, array decays into the pointer of FIRST element of array. One must define a rule, to let the method know the number of elements.
You declare char mbuf[16], you pass it to setName(), setName() will not get char[], but will get char* instead.
So, the declaration should be
static void setName(const char* str, char* buf)
Next, char mbuf[16] can only store 15 chars, because the last char has to be 'null terminator', which is '\0'. Otherwise, the following situation will occur:
// if I use buf in my code it is leading to spurious characters since length is greater than 16 .
Perhaps this will help you understand:
char str[] = "foobar"; // = {'f','o','o','b','a','r','\0'};
So the code should be
static void setName(const char* str, char* buf)
{
int sz = MIN(strlen(str), 15); // not 16
for (int i = 0; i < sz; i++) buf[i] = str[i];
buf[sz] = '\0'; // assert that you're assigning 'null terminator'
}
Also, I would recommend you not to reinvent the wheel, why don't use strncpy instead?
char mbuf[16];
strncpy(mbuf, "12345678901234567890", 15);
The following code passes the size of the memory allocated to the buffer, to the setName function.
That way the setName function can ensure that it does not write outside the allocated memory.
Inside the function either a for loop or strncpy can be used. Both will be controlled by the size parameter sz and both will require that a null terminator character is placed after the copied characters. Again, sz will ensure that the null terminator is written within the memory allocated to the buffer.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void setName(const char *str, char *buf, int sz);
int main()
{
const int a_sz = 16;
char* string = "This bit is OK!! but any more than 15 characters are dropped";
/* allocate memory for a buffer & test successful allocation*/
char *mbuf = malloc(a_sz);
if (mbuf == NULL) {
printf("Out of memory!\n");
return(1);
}
/* call function and pass size of buffer */
setName(string, mbuf, a_sz);
/* print resulting buffer contents */
printf("%s\n", mbuf); // printed: This bit is OK!
/* free the memory allocated to the buffer */
free(mbuf);
return(0);
}
static void setName(const char *str, char *buf, int sz)
{
int i;
/* size of string or max 15 */
if (strlen(str) > sz - 1) {
sz--;
} else {
sz = strlen(str);
}
/* copy a maximum of 15 characters into buffer (0 to 14) */
for (i = 0; i < sz; i++) buf[i] = str[i];
/* null terminate the string - won't be more than buf[15]) */
buf[i] = '\0';
}
Changing one value const int a_sz allows different numbers of characters to be copied. There is no 'hard coding' of the size in the function, so reducing the risk of errors if the code is modified later on.
I replaced MIN with a simple if ... else structure so that I could test the code.

Converting Structure to char* pointer in C

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

Overwriting parts of a string with parts of another string

I'm trying to overwrite a part of a string with parts of another String.
Basically, I want to access a given index of a string, write a given number of chars from another given index of another string.
So a function like memcpy(stringa[indexa], stringb[indexb], length);, except that this does not work.
Using strncpy would also suffice.
More code, as requested:
void mymemset(char* memloc, char* cmd, int data_blocks[], int len)
{
int i = 0;
while(i < len)
{
//missing part. Where I want the "memcpy" operation to take place
i++;
}
return;
}
memloc is the string we want to overwrite, cmd is the string we are overwriting from, data_blocks contains information about where in memloc we are supposed to write, and len is the number of operations we are executing. So I want to overwrite at location data_blocks[i], from cmd 8 chars at a time.
EDIT: I think I just forgot an &, so sorry to have confused you and thanks for your time. This seems to work:
void mymemset(char* memloc, char* cmd, int data_blocks[], int len)
{
int i = 0;
while(i < len)
{
memcpy(&memloc[data_blocks[i]], &cmd[i*8], 8);
i++;
}
return;
}
Takes 8 bytes at a time from cmd, stores them in memloc at the index given by data_blocks[i]. As commented, data_blocks contains information about different indexes in memloc that is available, and segmentation of the string cmd can occur.
Supposing stringa and stringb are declared as follows
char stringa[] = "Hello" ;
char stringb[] = "World" ;
This should work:
memcpy(&stringa[1], &stringb[1], 2) ;
Your example should not compile, or if it compiles if is likely to crash or to cause undefined behaviour :
memcpy(stringa[1], stringb[1], 2) ;
Your naming is confusing : memset works on bytes. If you manipulate strings you have extra precaution to take: think of the \0.
I think you want something like that:
void my_str_overwrite(char* dest, const char* ref, int idx, size_t count)
{
size_t input_len = strlen(dest);
if(input_len <= idx+count)
{
// Error: not enough space
}
for(size_t i=0; i<count; i++)
{
dest[idx+i] = ref[i];
}
return;
}
You don't need to pass the whole data_block[] array, you just interested in one element of this array which contains an offset for your copy, if I understood correctly.
As you don't modify cmd it should be const
The code above does not handle the NULL terminating byte which should be appended to memloc if it is actually a string
So I want to overwrite at location data_blocks[i], from cmd 8 chars at a time.
This one is confusing. If you know that you only want 8 bytes to be copied each time you call the function then in the code above make count an local variable within the function and fix it size_t count = 8;
if strings are the same size the you can just use memcpy:
#include <strings.h>
char text[] = "Hello James!";
char name[] = "Jenny";
char* pos = strstr(text, "James");
memcpy(pos, name, strlen(name)-1); // for the '\0'
If they're not then you must reallocate the string as the length will change
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define STR "Hello James!"
void replace(char** src, char* find, char* rep) {
char* ret = NULL;
char* pos = strstr(*src, find);
if (!pos)
return; // no changes
int l = (1 + strlen(*src) + strlen(rep) - strlen(find));
ret = (char*)malloc(sizeof(char) * l);
ret[l-1] = 0;
int ind = (int)(pos - *src);
strncpy(ret, *src, ind);
printf("ind: %d; %s\n", ind, ret);
strncpy(&ret[ind], rep, strlen(rep));
strncpy(&ret[ind+strlen(rep)], &pos[strlen(find)], strlen(pos)-strlen(find));
printf("%s\n", ret);
free(*src);
*src = ret;
}
int main() {
char *str = NULL;
str = (char*)malloc(sizeof(char) * (strlen(STR)+1));
assert(str);
strcpy(str, STR);
printf("before: %s\n", str);
replace(&str, "James", "John");
printf("after: %s\n", str);
free(str);
return 0;
}
This code in not optimized.

Returning arrays and pointers in C?

I'm relatively a beginner in programming in C and am getting super confused with arrays and pointers.
Basically what I'm trying to do is extend a string that contains binary to the designated length len; (i.e. len=8 for num[]=101 would produce "00000101").
Can someone help me understand what's wrong with this?
const char * extendBinary(char num[], int len) {
char *number = &num;
int length = len;
int difference;
if(strlen(*num)<len) {
difference = len-strlen(num);
while(difference>0)
{
&number = strcat("0", &number);
difference--;
}
}
return number;
}
Your problems start with your specification. If I understand you correctly, you want to have a function where you pass an array of characters and a length. The size of your array of input characters will be between 1 and len? However, your function has no way of knowing what the size of your array num is. If you wanted this to work, you would need to define your function as
const char * extendBinary(char *num, size_t num_len, int len);
so that your function doesn't overrun your buffer pointed to by num. Note that I replaced char num[] with char *num as this is the common mechanism for passing a pointer. You cant pass pointers to arrays and then dereference that pointer and get back the original type (that includes its size) -- that's just one thing that C doesn't let you do, so just use a normal pointer and a separate size variable.
Finally, you'll have to deal with memory allocation unless you want a memory leak. Thus, you could simply say that whom ever calls extendBinary should free it's return value when done with it.
const char * extendBinary(char *num, size_t num_len, int len) {
char *ret = malloc(len + 1);
int i;
memset(ret, '0', len);
ret[len] = 0;
strncpy(&ret[len - num_len], num, num_len);
return ret;
}
int main(void) {
char arr[] = {'1', '0', '1'};
const char *formatted = extendBinary(arr, sizeof(arr), 8);
printf("%s\n", formatted);
free(formatted);
return 0;
}
this is wrong.
strcat("0", &number);
A weird way to fix you code would be this:
char temp[32] = {};
...
...
while(difference>0)
{
strncat(temp, "0", 31 - strlen(temp));
difference--;
}
strncat(temp, num, 31 - strlen(temp));
strncpy(num, temp, len);
Note, I am writing this code just to help you understand how strcat() works, there is much better ways to do what you are trying to do.
You cannot concatenate something to a const string, you must have entire control of what is happening into you code, and where your code is writing. Do you know where is the pointer to "0" in your source?
How do you set up num? If it's really an array of characters rather than a string, there's no requirement that it be null terminated, unless it's a global/static. If you set it up like so in a function:
char str[10];
str[0] = '1';
str[1] = '0';
str[2] = '1';
than your strlen will get whatever, depending upon whatever junk happens to be in num.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//case 1: for num[9]="101";
char *extendBinary1(char num[], int len) {
int num_len = strlen(num);
memmove(num + (len - num_len), num, num_len);
memset(num, '0', (len - num_len));
return num;
}
//case 2: for "101";//pointer to const char
char *extendBinary2(const char num[], int len) {
int num_len = strlen(num);
char *number = calloc(len + 1, sizeof(char));
memset(number, '0', (len - num_len));
return strcat(number, num);
}
int main(void){
char num[9] = "101";
char *number = extendBinary2("101", 8);//dynamic allocate
printf("%s\n", extendBinary1(num, 8));
printf("%s\n", number);//free(number);
return 0;
}

String (array) capacity via pointer

I am tring to create a sub-routine that inserts a string into another string. I want to check that the host string is going to have enough capacity to hold all the characters and if not return an error integer. This requires using something like sizeof but that can be called using a pointer. My code is below and I would be very gateful for any help.
#include<stdio.h>
#include<conio.h>
//#include "string.h"
int string_into_string(char* host_string, char* guest_string, int insertion_point);
int main(void) {
char string_one[21] = "Hello mother"; //12 characters
char string_two[21] = "dearest "; //8 characters
int c;
c = string_into_string(string_one, string_two, 6);
printf("Sub-routine string_into_string returned %d and creates the string: %s\n", c, string_one);
getch();
return 0;
}
int string_into_string(char* host_string, char* guest_string, int insertion_point) {
int i, starting_length_of_host_string;
//check host_string is long enough
if(strlen(host_string) + strlen(guest_string) >= sizeof(host_string) + 1) {
//host_string is too short
sprintf(host_string, "String too short(%d)!", sizeof(host_string));
return -1;
}
starting_length_of_host_string = strlen(host_string);
for(i = starting_length_of_host_string; i >= insertion_point; i--) { //make room
host_string[i + strlen(guest_string)] = host_string[i];
}
//i++;
//host_string[i] = '\0';
for(i = 1; i <= strlen(guest_string); i++) { //insert
host_string[i + insertion_point - 1] = guest_string[i - 1];
}
i = strlen(guest_string) + starting_length_of_host_string;
host_string[i] = '\0';
return strlen(host_string);
}
C does not allow you to pass arrays as function arguments, so all arrays of type T[N] decay to pointers of type T*. You must pass the size information manually. However, you can use sizeof at the call site to determine the size of an array:
int string_into_string(char * dst, size_t dstlen, char const * src, size_t srclen, size_t offset, size_t len);
char string_one[21] = "Hello mother";
char string_two[21] = "dearest ";
string_into_string(string_one, sizeof string_one, // gives 21
string_two, strlen(string_two), // gives 8
6, strlen(string_two));
If you are creating dynamic arrays with malloc, you have to store the size information somewhere separately anyway, so this idiom will still fit.
(Beware that sizeof(T[N]) == N * sizeof(T), and I've used the fact that sizeof(char) == 1 to simplify the code.)
This code needs a whole lot more error handling but should do what you need without needing any obscure loops. To speed it up, you could also pass the size of the source string as parameter, so the function does not need to calculate it in runtime.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
signed int string_into_string (char* dest_buf,
int dest_size,
const char* source_str,
int insert_index)
{
int source_str_size;
char* dest_buf_backup;
if (insert_index >= dest_size) // sanity check of parameters
{
return -1;
}
// save data from the original buffer into temporary backup buffer
dest_buf_backup = malloc (dest_size - insert_index);
memcpy (dest_buf_backup,
&dest_buf[insert_index],
dest_size - insert_index);
source_str_size = strlen(source_str);
// copy new data into the destination buffer
strncpy (&dest_buf[insert_index],
source_str,
source_str_size);
// restore old data at the end
strcpy(&dest_buf[insert_index + source_str_size],
dest_buf_backup);
// delete temporary buffer
free(dest_buf_backup);
}
int main()
{
char string_one[21] = "Hello mother"; //12 characters
char string_two[21] = "dearest "; //8 characters
(void) string_into_string (string_one,
sizeof(string_one),
string_two,
6);
puts(string_one);
return 0;
}
I tried using a macro and changing string_into_string to include the requirement for a size argument, but I still strike out when I call the function from within another function. I tried using the following Macro:
#define STRING_INTO_STRING( a, b, c) (string_into_string2(a, sizeof(a), b, c))
The other function which causes failure is below. This fails because string has already become the pointer and therefore has size 4:
int string_replace(char* string, char* string_remove, char* string_add) {
int start_point;
int c;
start_point = string_find_and_remove(string, string_remove);
if(start_point < 0) {
printf("string not found: %s\n ABORTING!\n", string_remove);
while(1);
}
c = STRING_INTO_STRING(string, string_add, start_point);
return c;
}
Looks like this function will have to proceed at risk. looking at strcat it also proceeds at risk, in that it doesn't check that the string you are appending to is large enough to hold its intended contents (perhaps for the very same reason).
Thanks for everyone's help.

Resources