So I am working on a project in C that requires that I pass pointers to a struct into functions. The project is structured as follows:
struct structName {
unsigned short thing2;
char thing1[];
};
void function_1(struct structName *s) {
strcpy(s->thing1, "Hello");
printf("Function 1\n%s\n\n", s->thing1); // prints correctly
}
void function_2(struct structName *s) {
// can read thing2's value correctly
// thing1 comes out as a series of arbitrary characters
// I'm guessing it's an address being cast to a string or something?
printf("Function 2\n%s\n\n", s->thing1); // prints arbitrary characters ('É·/¨')
}
int main() {
struct structName s;
function_1(&s);
printf("Main\n%s\n\n", s.thing1);
function_2(&s);
printf("Main 2\n%s\n\n", s.thing1);
}
This code outputs the following:
Function 1
Hello
Main
Hello
Function 2
É·/¨
Main 2
É·/¨
Obviously, the program has more than just what I've written here; this is just a simplified version; so if there's anything I should check that might be causing this let me know. In all honesty I reckon it's probably just a stupid rookie error I'm making somewhere.
[EDIT: Seems like s.thing1 is being mutated in some way in the call to function_2(), since the odd value is replicated in main() - I should point out that in my program the printf()s are located right before the function call and in the first line of the function, so there's no chance that it's being written to by anything I'm doing. I've updated the example code above to show this.]
Thanks in advance!
The structure contains a flexible member at its end, if you declare a static object with this type, the length of this member will be zero, so strcpy(s->thing1, "Hello"); will have undefined behavior.
You are supposed to allocate instances of this type of structure with enough extra space to handle whatever data you wish to store into the flexible array.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct pstring {
size_t length;
char data[];
} pstring;
pstring *allocate_pstring(const char *s) {
size_t length = strlen(s);
pstring *p = malloc(sizeof(*p) + length + 1);
if (p != NULL) {
p->length = length;
strcpy(p->data, s);
}
return p;
}
void free_pstring(pstring *p) {
free(p);
}
int main() {
pstring *p = allocate_pstring("Hello");
printf("Main\n%.*s\n\n", (int)p->length, p->data);
free_pstring(p);
return 0;
}
I am trying to use the first few bytes of a section of memory on the heap to store meta-data about the section memory using C language (not C++).
The heap space is created using:
char* start_mem = (char*)malloc(10*sizeof(char)); //10 bytes of memory
Now, I'm trying to place a 'meta' struct in the first 4 bytes of allocated heap space.
typedef struct{
int test;
}meta_t;
This is a test code I'm using to just understand how to do it before I implement it in the larger code.
test #include <stdio.h>
typedef struct{
int test;
} meta_t;
int main(void) {
char* start_mem = (char*)malloc(10*sizeof(char));
meta_t meta;
meta.test = 123;
return 0;
}
Side note: Why does this type cast work:
int test = 123;
char c = (char) test;
but this type cast doesn't?:
meta_t meta;
meta.test = 123;
char c = (char) meta;
The main question is how can I fit the 'meta' data type (4 bytes) in to four char sized (1 byte) spaces at the start of the start_mem?
FYI - This is a small part of a larger project in a data structures class. Having said that there is no need to reply with "Why would you even bother to do this?" or "You could just use function_abc() and do the same thing." Restrictions have been set (i.e. a single use of malloc() ) and I would like to follow them.
You could use memcpy:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
int test;
} meta_t;
int main() {
char *start_mem = malloc(10);
meta_t meta;
meta.test = 123;
memcpy(start_mem, &meta, sizeof(meta));
printf("Saved: %d\n", ((meta_t *)(start_mem))->test);
return 0;
}
What about this one?
memcpy(start_mem, &meta, sizeof meta);
Note that you have to pay attention to endianness.
Even more simple, do a typecasted assignment:
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int test;
} meta_t;
int main() {
char *start_mem = malloc(10);
meta_t meta;
meta_t *p;
meta.test = 123;
p = (meta_t *) start_mem;
*p = meta;
printf("Saved: %d\n", ((meta_t *)(start_mem))->test);
return 0;
}
Hey all I'm having some trouble diagnosing the reason for an error in printing an array of structures in C.
In a separate header file (call it header.h) I have the following typedef'd structure:
typedef struct instruction prog;
struct instruction{
char kind;
char op[4];
};
For my main programing task I want to read from a file a series of what are supposed to be instructions consisting of a type character (the variable kind above) and an instruction consisting of four integers (listed as op above). Examples include R 1004 E 1008, etc. I can read the data in just fine but it seems to be storing things improperly. I wrote the following test code to see if I could find the error but I was still getting the same issue. My goal is to store these as an array of instructions where, using the parlance of the code below, mem[i].kind = 'R' and mem[i].op =1004`.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include "header.h"
void memFill(prog *P, int x);
void memPrint(prog *P, int x);
int main(){
prog mem[10];
memFill(&mem[0], 10);
memPrint(&mem[0], 10);
return 0;
}
void memFill(prog *P, int x){
char *v = "1004";
for(int i = 0; i< x; i++){
P->kind = 'R';
strcpy(P->op, v);
P++;
}
}
void memPrint(prog *P, int x){
for(int i = 0; i <x; i++){
printf("%c %s\n",P->kind, P->op);
P++;
}
}
This is giving me output that looks like this:
R 1004R1004R1004R1004R1004R1004R1004R1004R1004R1004
R 1004R1004R1004R1004R1004R1004R1004R1004R1004
R 1004R1004R1004R1004R1004R1004R1004R1004
R 1004R1004R1004R1004R1004R1004R1004
R 1004R1004R1004R1004R1004R1004
R 1004R1004R1004R1004R1004
R 1004R1004R1004R1004
R 1004R1004R1004
R 1004R1004
R 1004
The reason this is weird is that identical pointer arithmetic has given just fine results with a similar structure. What's going on here? What am I missing?
Buffer overflow on char op[4], then Undefined_behavior
To be able to store "1004" it have to be 5 bytes long to have space for NULL terminator.
struct instruction{
char kind;
char op[5];
};
Literal string "1004" is '1', '0', '0', '4', '\0'
You forgot to give space for the string ending null.
Fix your struct declaration to this:
struct instruction{
char kind;
char op[5];
};
And it will work.
You can also simplify declaration this way:
typedef struct instruction{
char kind;
char op[5];
} prog;
struct MemoryTag1;
typedef struct MemoryTag1{
char a[8]= {'+','0','2','6','.','5','EA','\r'}; // setpoint temperature value
char b[8]= {'-','0','2','4','.','5','EB','\r'};
char c[6]= {'+','0','2','0','EC','\r'};
}Memory1;
// This is a message structure which I want to transfer over the serial interface (RS232) and later convert into integer value. please guide me in this.
Your syntax is a bit off - try this:
// declare Memory1 struct type to hold data
typedef struct MemoryTag1 {
char a[9]; // setpoint temperature value
char b[9];
char c[7];
} Memory1;
// allocate and initialise a Memory1 struct
Memory1 m = { {'+','0','2','6','.','5','E','A','\r'},
{'-','0','2','4','.','5','E','B','\r'},
{'+','0','2','0','E','C','\r'} };
Really, to be honest, I'd prefer more information. But it doesn't really matter. It only affects the method of output. If you were running this on an arduino, for instance, you could output to the serial ports as easily as:
Serial.begin(9600);
Serial.write('a');
etc, etc
As others have mentioned, there are situations in which you'd be better off using null-terminated strings. If however, you had a particular reason to do so, then I suppose you could;
#include <stdio.h>
typedef struct memoryTag1_t
{
char a[9]; // setpoint temperature value
char b[9];
char c[7];
} *pMemoryTag1_t;
typedef struct memoryTag2_t
{
char a[10]; // setpoint temperature value
char b[10];
char c[8];
} *pMemoryTag2_t;
void displayField1(char *field, int len)
{
for (int i=0; i<len; i++)
{
if (i!=0) printf(",");
printf("%c", field[i]);
}printf("\n");
}
void displayField2(char *field)
{
bool firstDone = false;
while (*field)
{
if (firstDone)
printf(",");
else
firstDone = true;
printf("%c", *field++);
}
printf("\n");
}
int main()
{
memoryTag1_t myMem1 =
{
{'+','0','2','6','.','5','E','A','\r'},
{'-','0','2','4','.','5','E','B','\r'},
{'+','0','2','0','E','C','\r'}
};
memoryTag2_t myMem2 =
{
"+026.5EA\r",
"-024.5EB\r",
"+020EC\r"
};
displayField1(myMem1.a, sizeof(myMem1.a));
displayField1(myMem1.b, sizeof(myMem1.b));
displayField1(myMem1.c, sizeof(myMem1.c));
displayField2(myMem2.a);
displayField2(myMem2.b);
displayField2(myMem2.c);
}
Output:
(Don't forget there's a \r printed 'after' the last comma in each line)
+,0,2,6,.,5,E,A,
-,0,2,4,.,5,E,B,
+,0,2,0,E,C,
+,0,2,6,.,5,E,A,
-,0,2,4,.,5,E,B,
+,0,2,0,E,C,
you can not declare struct in C in this way:
it should be
typedef struct MemoryTag1{
char a[9];
char b[9];
char c[7];
}Memory1;
you can set value in the declaration of an object of this structure:
Memory1 test = {
{'+','0','2','6','.','5','E','A','\r'},
{'-','0','2','4','.','5','E','B','\r'},
{'+','0','2','0','E','C','\r'}
};
If you use this bloc in each initiation of a Memory1 object so you can use macro to make it easier:
#define INIT_MEMORYTAG1 {\
{'+','0','2','6','.','5','E','A','\r'},\
{'-','0','2','4','.','5','E','B','\r'},\
{'+','0','2','0','EC','\r'}\
}
and then in your declaration of a Memory1 object:
Memory1 test = INIT_MEMORYTAG1;
BTW: You can not put 'EA', 'EB', 'EC' like a 1 charachter you have to separate them to:
'E','A', 'E','B', 'E','C' and so you have to update your char array sizes in the struct definition
That is really not C syntax.
You can't have initializers in declarations of types, that doesn't have any meaning.
You need to do it like this, to build the message:
typedef struct {
char a[10];
char b[10];
char c[8];
} Memory1;
int main(void)
{
Memory1 m1;
strcpy(m1.a, "+026.5EA\r");
strcpy(m1.b, "-024.5EB\r");
strcpy(m1.c, "+020EC\r");
return 0;
}
Note that the above will build proper C strings in the fields of the message, i.e. there will be 0-characters acting as terminators. The sizes were too small, so I changed that.
It's trivial to ignore the terminator characters if you need to send this over some format that doesn't allow them; send each field separately.
Converting one of the fields back into integers could be done using sscanf(), for instance.
I'm testing the judy arrays implementation on ubuntu 11.10 "libjudy-dev".
I'm encounter with a strange behavior, possible bug. related to the size of val and the key.
In the example, if i use the struct TEST with only 1 int with large keys works, but if i use the 10 int struct with the same key it doesn't, the 10 int struct works ok with small keys.
judy manpage
In the man page said that the string can be any size.
#include <stdio.h>
#include <string.h>
#include <Judy.h>
/*struct TEST {
unsigned int size9;
};*/
struct TEST {
unsigned int size0;
unsigned int size1;
unsigned int size2;
unsigned int size3;
unsigned int size4;
unsigned int size5;
unsigned int size6;
unsigned int size7;
unsigned int size8;
unsigned int size9;
};
int main()
{
struct TEST *val;
char key[1024];
Pvoid_t array = NULL;
//strcpy(key, "0123456789_0123456789");
strcpy(key, "0123456789_0123456789_0123456789");
JSLI(val, array, key);
val->size9 = 10;
val = NULL;
JSLG(val, array, key);
if(val == NULL) {
printf("NULL\n");
} else {
printf("%u\n", val->size9);
}
return 0;
}
JudySL "maps" a string to a word in RAM. This word is used as a "word_t" or a "pointer to more memory". The routines return (val in your case) a pointer to the word available for your use.
Your code makes that pointer (val) a pointer to a struct of greater size than one word -- thus
destroying part of the internal Judy data structure with the statement "val->size9 = 10;".
Keep in mind that the "key" is a string, and the PValue is a pointer to an object of size word. If you want *PValue to point to struct TEST and it is bigger than a word_t then memory must be allocated for it. Your test program seems to want to map a string to a struct TEST--
struct TEST is bigger than a word_t.
Doug Baskins