Trouble Copying Char* to Char* in C - c

I have the following program I am trying to run but surely, due to my lack of good knowledge, my program crashes runtime:
#include <stdio.h>
#include "ptref.h"
mystruct_t *FRSt = NULL;
int main(int argc, char* argv[])
{
char ct[2] = {0, 1, '\0'};
char dd[2] = {0, 1, '\0'};
populate_contents(FRSt, 2, "FRES", ct, dd);
return 0;
}
HEADER
/*
* ptref.h
*
*/
#ifndef PTREF_H_
#define PTREF_H_
typedef struct mystruct
{
char* ct[2]; //
char* dd[2]; // = "0\0";
char* name[]; // = "1\0";
} mystruct_t;
extern mystruct_t p;
void populate_contents(mystruct_t* mystruct_var, int arrSize, char* name[], char* dd[], char* ct[])
{
/* Initialise arrays */
int i;
i = 0;
strncpy(mystruct_var->name, name, sizeof(name));
for (i = 0; i < arrSize; i++)
{
mystruct_var->dd[i] = dd[i];
mystruct_var->ct[i] = ct[i];
}
return;
}
#endif /* PTREF_H_ */
Because I am going to implement this in a real-time computer, I am not sure if using malloc will cause me any trouble. However, I have got a feeling that because I have not used malloc for my mystruct_var pointer, I am having trouble, or may be it is my moronic code. In any way, further education and advise will be highly appreciated.
P.S. I have looked into the other relevant post but my problem is quite different. So, I posed a new question.

Firstly, in main() char ct[2] = {0, 1, '\0'}; this particular array initialization is incorrect as you have defined array size as 2 and initializing 3 array elements.
In function populate_contents(FRSt, 2, "FRES", ct, dd);, the third argument is a character string which corresponding called function argument should be a char array as char name[] or char pointer as char *name. It should not be as you defined name as array of pointers char *name[]. Same thing goes for arguments passed ct & dd, they should be just char pointers in the callee function as there type is char *.
Also your structure mystruct_t declared is incorrect by the way looking at your usage of member elements.
As said by Grijesh, sizeof(name) is what you don't want as name is a pointer which could be 4 or 8 Bytes, so make use of strlen() to get the length of the string you received.

Related

Access structure member char* using offsets

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);

How to initialize struct char array?

I'm having trouble initializing a string of characters belonging to a struct. "Expression must have a modifiable lvalue". Do I need to use strcopy? I am not quite sure how to utilize this. Here is my code:
typedef struct {
char name[50];
int attackDamage;
int magicDamage;
int defense;
int power;
int type;
} ITEM;
int main() {
ITEM item[10];
char itemset[5][5] = { 0 };
char champion1[] = "Gnar";
char champion2[] = "Vi";
char champion3[] = "Fizz";
char champion4[] = "Draven";
char champion5[] = "Braum";
item[0].name = "Brutalizer"; // Having issues here
}
EDIT: I did this and seems there isn't anymore errors. Is this the proper way?
strcpy(item[0].name, "Brutalizer");
item[0].name is an array, you cannot assign a pointer (string literal) to an
array. You need to copy the contents, in this case with strcpy for example:
strcpy(item[0].name, "Brutalizer");
Or if the length of the source is not know beforehand, then you can use
strncpy to avoid buffer overflows:
strncpy(item[0].name, "Brutalizer", sizeof item[0].name);
item[0].name[sizeof(item[0].name) - 1] = '\0'; // make sure that it's \0-terminated
or you can use snprintf
snprintf(item[0].name, sizeof item[0].name, "Brutalizer");

What is a good way to allocate a sized string buffer on the stack?

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 []

How to return a multidimensional character array from a function in a header file in C

I have a main file, and a header file.
In main file, I want to return a 2D char array from a char function from header file. My char function is as following:
char character_distribution(int length, char redistribution[length][2])
{
char *buffer, distribution[256][2] = {0};
long lSize;
struct Bar result = funct();
buffer = result.x;
lSize = result.y;
length = collect_character_distribution(buffer, lSize, distribution);
reorganize_character_distribution(length, distribution, redistribution);
return redistribution;
}
And my main function is as follows:
#include <stdio.h>
#include "character_distribution.h"
void main()
{
int length;
char distribution[length][2];
distribution = character_distribution(length, distribution[length][2]);
int a;
for(a = 0; a < length; a++)
{
printf("%c\n", distribution[a][0]);
}
}
When I run my code, I get the following error:
warning: return makes integer from pointer without a cast
How can I fix the problem?
void character_distribution(int length, char redistribution[][2])
{
char *buffer, distribution[256][2] = {0};
long lSize;
struct Bar result = funct();
buffer = result.x;
lSize = result.y;
length = collect_character_distribution(buffer, lSize, distribution);
reorganize_character_distribution(length, distribution, redistribution);
}
int main()
{
int length = 2; //initialize
char distribution[length][2];
character_distribution(length, distribution);
int a;
for(a = 0; a < length; a++)
{
printf("%c\n", distribution[a][0]);
}
return 0;
}
If you really have to return the 2d array, one way (easy way) is to just put it in a struct
struct distribution_struct {
char x[256];
char y[2];
};
struct distribution_struct character_distribution(int length, char redistribution[][2]) {
struct distribution_struct dis;
//initialize the struct with values
//return the struct
}
And another way is to manually allocate memory for the 2d array in the function and return it
char** character_distribution(int length, char redistribution[][2]) {
//use malloc to create the array and a for loop to populate it
}
You cannot actually return an array from a C function. You can, however, return a pointer to such an array. The correct declaration in that case is:
char (*character_distribution(int length, char redistribution[][2]))[][2]
Sizing the initial dimension is not necessary and not, I suspect, actually conformant with standard C (at least, sizing it with length as you did in your question looks dubious to me). This is because arrays are passed by reference implicitly (and in this case, returned by reference explicitly) and it is not necessary to know the first dimension in order to calculate the address of an element having been given a pointer to the array (and the indices).
Note that you should not return a pointer to an array that is scoped locally to the function, since its storage is deallocated once the function returns (and such a pointer would then be invalid).
However, your question shows that you don't really need to return an array. Since arrays are passed by reference anyway, altering the passed-in array will causes changes that are also visible to the caller. Your code could be written as:
void character_distribution(int length, char redistribution[][2])
{
char *buffer, distribution[256][2] = {0};
long lSize;
struct Bar result = funct();
buffer = result.x;
lSize = result.y;
length = collect_character_distribution(buffer, lSize, distribution);
reorganize_character_distribution(length, distribution, redistribution);
}
And
#include <stdio.h>
#include "character_distribution.h"
void main()
{
int length = 256; // you need to initialise this...
char distribution[length][2];
// No assignment needed here!:
character_distribution(length, distribution /* [length][2] - remove this! */);
int a;
for(a = 0; a < length; a++)
{
printf("%c\n", distribution[a][0]);
}
}
(Of course this relies on the various other functions you call performing as they are supposed to).
Change the signature to this:
char** character_distribution(int length, char redistribution[length][2])
You are returning a multidimensional array, not a character.

Declaring Pascal-style strings in C

In C, is there a good way to define length first, Pascal-style strings as constants, so they can be placed in ROM? (I'm working with a small embedded system with a non-GCC ANSI C compiler).
A C-string is 0 terminated, eg. {'f','o','o',0}.
A Pascal-string has the length in the first byte, eg. {3,'f','o','o'}.
I can declare a C-string to be placed in ROM with:
const char *s = "foo";
For a Pascal-string, I could manually specify the length:
const char s[] = {3, 'f', 'o', 'o'};
But, this is awkward. Is there a better way? Perhaps in the preprocessor?
I think the following is a good solution, but don't forget to enable packed structs:
#include <stdio.h>
#define DEFINE_PSTRING(var,str) const struct {unsigned char len; char content[sizeof(str)];} (var) = {sizeof(str)-1, (str)}
DEFINE_PSTRING(x, "foo");
/* Expands to following:
const struct {unsigned char len; char content[sizeof("foo")];} x = {sizeof("foo")-1, "foo"};
*/
int main(void)
{
printf("%d %s\n", x.len, x.content);
return 0;
}
One catch is, it adds an extra NUL byte after your string, but it can be desirable because then you can use it as a normal c string too. You also need to cast it to whatever type your external library is expecting.
GCC and clang (and possibly others) accept the -fpascal-strings option which allows you to declare pascal-style string literals by having the first thing that appears in the string be a \p, e.g. "\pfoo". Not exactly portable, but certainly nicer than funky macros or the runtime construction of them.
See here for more info.
You can still use a const char * literal and an escape sequence as its first character that indicates the length:
const char *pascal_string = "\x03foo";
It will still be null-terminated, but that probably doesn't matter.
It may sound a little extreme but if you have many strings of this kind that need frequent updating you may consider writing your own small tool (a perl script maybe?) that runs on the host system, parses an input file with a custom format that you can design to your own taste and outputs a .c file. You can integrate it to your makefile or whatever and live happily ever after :)
I'm talking about a program that will convert this input (or another syntax that you prefer):
s = "foo";
x = "My string";
To this output, which is a .c file:
const char s[] = {3, 'f', 'o', 'o'};
const char x[] = {9, 'M', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g'};
My approach would be to create functions for dealing with Pascal strings:
void cstr2pstr(const char *cstr, char *pstr) {
int i;
for (i = 0; cstr[i]; i++) {
pstr[i+1] = cstr[i];
}
pstr[0] = i;
}
void pstr2cstr(const char *pstr, char *cstr) {
int i;
for (i = 0; i < pstr[0]; i++) {
cstr[i] = pstr[i+1];
}
cstr[i] = 0;
}
Then I could use it this way:
int main(int arg, char *argv[]) {
char cstr[] = "ABCD", pstr[5], back[5];
cstr2pstr(cstr, pstr);
pstr2cstr(pstr, back);
printf("%s\n", back);
return 0;
}
This seems to be simple, straightforward, less error prone and not specially awkward. It may be not the solution to your problem, but I would recommend you to at least think about using it.
You can apply sizeof to string literals as well. This allows a little less awkward
const char s[] = {sizeof "foo" - 1u, 'f', 'o', 'o'};
Note that the sizeof a string literal includes the terminating NUL character, which is why you have to subtract 1. But still, it's a lot of typing and obfuscated :-)
One option might be to abuse the preprocessor. By declaring a struct of the right size and populating it on initialization, it can be const.
#define DECLARE_PSTR(id,X) \
struct pstr_##id { char len; char data[sizeof(X)]; }; \
static const struct pstr_##id id = {sizeof(X)-1, X};
#define GET_PSTR(id) (const char *)&(id)
#pragma pack(push)
#pragma pack(1)
DECLARE_PSTR(bob, "foo");
#pragma pack(pop)
int main(int argc, char *argv[])
{
const char *s = GET_PSTR(bob);
int len;
len = *s++;
printf("len=%d\n", len);
while(len--)
putchar(*s++);
return 0;
}
This is why Variable Length Arrays were introduced in c99 (and to avoid the use of the "struct hack") IIRC, Pascal-strings were limited to a maximal length of 255.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h> // For CHAR_BIT
struct pstring {
unsigned char len;
char dat[];
};
struct pstring *pstring_new(char *src, size_t len)
{
struct pstring *this;
if (!len) len = strlen(src);
/* if the size does not fit in the ->len field: just truncate ... */
if (len >=(1u << (CHAR_BIT * sizeof this->len))) len = (1u << (CHAR_BIT * sizeof this->len))-1;
this = malloc(sizeof *this + len);
if (!this) return NULL;
this->len = len;
memcpy (this->dat, src, len);
return this;
}
int main(void)
{
struct pstring *pp;
pp = pstring_new("Hello, world!", 0);
printf("%p:[%u], %*.*s\n", (void*) pp
, (unsigned int) pp->len
, (unsigned int) pp->len
, (unsigned int) pp->len
, pp->dat
);
return 0;
}
You can define an array in the way you like, but note that this syntax is not adequate:
const char *s = {3, 'f', 'o', 'o'};
You need an array instead of a pointer:
const char s[] = {3, 'f', 'o', 'o'};
Note that a char will only store numbers up to 255 (considering it's not signed) and this will be your maximum string length.
Don't expect this to work where other strings would, however. A C string is expected to terminate with a null character not only by the compiler, but by everything else.
Here's my answer, complete with an append operation that uses alloca() for automatic storage.
#include <stdio.h>
#include <string.h>
#include <alloca.h>
struct pstr {
unsigned length;
char *cstr;
};
#define PSTR(x) ((struct pstr){sizeof x - 1, x})
struct pstr pstr_append (struct pstr out,
const struct pstr a,
const struct pstr b)
{
memcpy(out.cstr, a.cstr, a.length);
memcpy(out.cstr + a.length, b.cstr, b.length + 1);
out.length = a.length + b.length;
return out;
}
#define PSTR_APPEND(a,b) \
pstr_append((struct pstr){0, alloca(a.length + b.length + 1)}, a, b)
int main()
{
struct pstr a = PSTR("Hello, Pascal!");
struct pstr b = PSTR("I didn't C you there.");
struct pstr result = PSTR_APPEND(PSTR_APPEND(a, PSTR(" ")), b);
printf("\"%s\" is %d chars long.\n", result.cstr, result.length);
return 0;
}
You could accomplish the same thing using c strings and strlen. Because both alloca and strlen prefer short strings I think that would make more sense.

Resources