I developing a C embedded software that build a JSON string with several parameters ( string and integer ). For my purpose I used cJSON ) in future I need to parse complex JSON).
I build my json with this code:
jsonObject = cJSON_CreateObject();
cJSON_AddNumberToObject( jsonObject, "Version", 1 );
cJSON_AddStringToObject( jsonObject, "ID", "xyz" );
cJSON_AddStringToObject( jsonObject, "Local", "1234" );
cJSON_AddNumberToObject( jsonObject, "Type", 1 );
cJSON_AddStringToObject( jsonObject, "Message", "Hello" );
Next I print the JSON into a dynamic buffer using:
cJSON_PrintPreallocated( jsonObject, *jsonMessage, *jsonMessageLen, 0 )
When I visualise the jsonMessage on a terminal, the property "Type" hasn't a value.
This is the built json:
{"Version":1,"ID":"xyz","Local":"123","Type":,"Message":"Hello"}
I try to use a different print method, for example I used:
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
And the JSON is built correctly. The problem is that I need to allocate the memory by myself and not using cJSON_PrintBuffered. This because I cannot use malloc and free function.
Any suggestions?
Thanks
I updated the cJSON module and now it works fine.
This is kind of interesting, I believe I know what is going on. Sorry for any inconveniences I caused by writing that bug ...
In version 1.4.0 I introduced a bug to cJSON that the function that prints numbers didn't fail when it couldn't allocate enough memory.
print_number will try to allocate 64 bytes of memory before printing a number, because it doesn't know how many bytes sprintf will need and snprintf is not available in ANSI C. Your preallocated buffer probably wasn't long enough for the 64 bytes, so it didn't print the number one, but then continued printing the rest of the JSON normally because it didn't fail (the bug).
I added a note to the header file today: Your preallocated has to be 63 bytes longer than what you expect the printed json to be if you want to avoid any kind of out of situation where cJSON aborts because it thinks it doesn't have enough memory in the preallocated buffer.
Related
I am getting an array of strings via a function call over D-Bus as follows. I am using GLib then to parse the returned values. The code below is greatly simplified. I can read each string returned using g_variant_iter_loop and the iterator.
How can I first determine how many strings have been returned in the array?
I need to allocate memory dynamically first depending on how many strings have been returned, before reading the actual strings.
This may seem simple, but i've been looking online for the best way to do this without success. Thanks in advance.
GVariant * val_returned = g_dbus_connection_call_sync(connection,
SERVICE,
OBJECT,
IFACE,
"GetStringsArray",
NULL,
G_VARIANT_TYPE("(as)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&err);
g_autoptr(GVariantIter) iterator = NULL;
g_variant_get(val_returned, "(as)", &iterator);
// Need to determine how many strings have been read into the array
// Use g_variant_iter_loop to retrieve each string as a gchar*
Call g_variant_iter_n_children (iterator).
Without using the string.h functions (want to use only the std libs), I wanted to create a new string by concatenating the string provided as an argument to the program. For that, I decided to copy the argument to a new char array of larger size and then replace the end of the string by the characters I want to append.
unsigned int argsize=sizeof(argv[1]);
unsigned char *newstr=calloc(argsize+5,1);
newstr=argv[1]; //copied arg string to new string of larger size
newstr[argsize+4]=oname[ns]; //copied the end-of-string null character
newstr[argsize]='.'; //this line gives seg fault
newstr[argsize+1]='X'; //this executes without any error
I believe there must be another more secure way of concatenating string without using string functions or by copying and appending char by char into a new char array. I would really want to know such methods. Also, I'm curious to know what is the reason of this segfault.
Read here: https://stackoverflow.com/a/164258/1176315 and I guess, the compiler is making my null character memory block read only but that's only a guess. I want to know the real reason behind this.
I will appreciate all your efforts to answer the question. Thanks.
Edit: By using std libs only, I mean to say I don't want to use the strcpy(), strlen(), strcat() etc. functions.
Without using the string.h functions (want to use only the std libs)
string.h is part of the standard library.
unsigned int argsize=sizeof(argv[1]);
This is wrong. sizeof does not tell you the length of a C string, it just tell you how big is the type of its argument. argv[1] is a pointer, and sizeof will just tell you how big a pointer is on your platform (typically 4 or 8), regardless of the actual content of the string.
If you want to know how long is a C string, you have to examine its characters and count until you find a 0 character (which incidentally is what strlen does).
newstr=argv[1]; //copied arg string to new string of larger size
Nope. You just copied the pointer stored in argv[1] to the variable newstr, incidentally losing the pointer that calloc returned to you previously, so you have also a memory leak.
To copy a string from a buffer to another you have to copy its characters one by one until you find a 0 character (which incidentally is what strcpy does).
All the following lines are thus operating on argv[1], so if you are going out of its original bounds anything can happen.
I believe there must be another more secure way of concatenating string without using string functions or by copying and appending char by char into a new char array.
C strings are just arrays of characters, everything boils down to copying/reading them one at time. If you don't want to use the provided string functions you'll end up essentially reimplementing them yourself. Mind you, it's a useful exercise, but you have to understand a bit better what C strings are and how pointers work.
First of all sizeof(argv[1]) will not return the length of the string you need to count the number of characters in the string using loops or using standard library function strlen().second if you want to copy the string you need to use strcpy() function.
You supposed to do like this:
unsigned int argsize=strlen(argv[1]); //you can also count the number of character
unsigned char *newstr=calloc((argsize+5),1);
strcpy(newstr,argv[1]);
newstr[argsize+4]=oname[ns];
newstr[argsize]='.';
newstr[argsize+1]='X';
I malloc'd an array of structures called "locations". In said structure is an element called "country". I created a string you can see below that holds "United States" in it. I malloc'd space to hold the string (it's required that I do so) and attempted to use strncpy to place the string into the malloced space.
This works elsewhere in my code with strings that are read in from a file, but not for this string which I declared directly.
When I print out the result, it says the structure is holding "United State(error symbol)"
So in place of the s at the end of "United States" is the error symbol.
The error symbol looks like a small box of ones and zeros.
char *US_string = "United States";
locations[0].country = malloc(sizeof(US_string));
strncpy(locations[0].country, US_string, strlen(US_string));
Anyone know what's going on?
Thanks for any help! And please try not to be too hard on me, I'm a first year CS major. Just trying to get this bug out of a lab.
mallocing need to be adjusted by adding 1to account for '\0'. Moreover sizeof(US_string) will give size of pointer, which may be different from actual string size. Hence
locations[0].country = malloc(strlen(US_string) + 1);
and missing locations[0].country[strlen(US_string)] = '\0'
sizeof will return the pointer size, not the string size. Use strlen +1 (to account for the 0 string termination char):
locations[0].country = malloc(strlen(US_string)+1);
I am writing a program and I need to initialize a message buffer which will hold text. I am able to make it work, however I am writing below various ways used to initialize the strings in C and I want to understand the difference. Also, which is the most appropriate method for initializing a wchar_t/char string?
Method I:
wchar_t message[100];
based on my understanding, this will allocate a memory space of 200 bytes (I think size of wchar_t is 2 bytes on Windows OS). This memory allocation is static and it will be allocated inside the .data section of the executable at the time of compiling.
message is also a memory address itself that points to the first character of the string.
This method of initializing a string works good for me.
Method II:
wchar_t *message;
message=(wchar_t *) malloc(sizeof(wchar_t) * 100);
This method will first initialize the variable message as a pointer to wchar_t. It is an array of wide characters.
next, it will dynamically allocate memory for this string. I think I have written the syntax for it correctly.
When I use this method in my program, it does not read the text after the space in a string.
Example text: "This is a message"
It will read only "This" into the variable message and no text after that.
Method III:
wchar_t *message[100];
This will define message as an array of 100 wide characters and a pointer to wchar_t. This method of initializing message works good. However, I am not sure if it is the right way. Because message in itself is pointing to the first character in the string. So, initializing it with the size, is it correct?
I wanted to understand it in more depth, the correct way of initializing a string. This same concept can be extended to a string of characters as well.
The magic is the encoding-prefix L:
#include <wchar.h>
...
wchar_t m1[] = L"Hello World";
wchar_t m2[42] = L"Hello World";
wchar_t * pm = L"Hello World";
...
wcscat(m2, L" again");
pm = calloc(123, sizeof *pm);
wcspy(pm, L"bye");
See also the related part of the C11 Standard.
It really depends on what you want to do and how you use the data. If you need it globally, by all means, define a static array. If you only need it in a method, do the same in the method. If you want to pass the data around between functions, over a longer lifetime, malloc the memory and use that.
However, your method III is wrong - it is an array of 100 wchar_t pointers. If you want to create a 100 large wchar_t array and a pointer, you need to use:
wchar_t message[100], *message_pointer;
Also, concerning terminology: you are only declaring a variable in the method I, you never assign anything to it.
I am writing an app with the following dynamic config structure:
typedef struct {
char apphash[41];
char filenames_count;
char * filename[64];
} config;
But this code is wrong, I can't figure out how to copy data from and to c->filename[0] properly; c is a pointer to config structure, allocated dynamically like
config * c = (config *) malloc( 42 + 64 * 2 ) // alloc for 2 filenames. can realloc() later.
It segfaults if I use something like strcpy(c->filename[0],"file1.txt").
Can someone please help me with this?
Currently, I'm using direct address calculation, like
strcpy(
(char*)
((unsigned long) c + 42 /* apphash + filenames_count */ +
64 * 0 /* first item */ ),
"file1.txt"
);
and it works of course.
You see, I'm more of assembly programmer than of C, but I'd like this code to be more human-readable. This code looks that bad because I'm newcomer in C.
Oh, I gave a bad description of the situation. Sorry for that :(
The real code looks like:
config * c = (config*) malloc( 42 + 64 * 2 );
// we may realloc() it later if we are going to add more filenames.
// failing example how I do copy one default filename
strcpy(c->filename[0],"file1.txt");
// working example (i386)
strcpy((char*)((unsigned long) c + 42 + 64 * 0),"file1.txt");
I am using fully static structure type because it is going to be loaded directly from a file next time. That's why I can't really use pointers inside the structure, I need real data to be placed there.
I do check all lengths, no BOFs in real code, I just omitted all that stuff here.
I still didn't find a good solution to this.
Thanks again and sorry for bad question information.
I assume you have many filenames since you have filenames_count. Try
config_obj.filename[0] = strdup("file1.txt")
In your struct you're allocating an array of pointers to chars, not an array of chars. You must explicitely allocate also the targets of pointers, or at the very least, make the struct contain also the arrays of chars themselves:
char filename[64][MAX_PATH+1];
Replace MAX_PATH with the maximum length of any filename. Mind that this is not a very elegant solution, albeit a really simple one, because you're wasting lots of space.
Your direct address calculation is doing something different: it's placing the string directly in the space allocated for the pointers (and this is a Terribly Wrong Thing To Do™)
Right now config is a type that means the struct you have defined. You don't show us an identifier referring to an actual variable of type config.
So, first thing we need an instance of type config. You will either do
config c;
... c.filename ...
note the structure access operator is a ., or you will do something like
config *p = malloc(config)
/* error checking */
...c->filename ...
where -> is the pointer-dereference-and-access operator. The first form is preferred unless you hve a reason to want dynamic allocation (which, alas, happens a lot in c).
Then you have to figure out just what you want filename to be. As it is you have allocated space for 64 character pointers which don't point at allocated memory (except by purest acident, and then not at the memory you mean). You probably wanted{*} char filename[64] (a single filename allowed to be up to 63 characters long (to leave room for the null termination)) in which case you would use
strcpy(c.filename,"file1.txt");
/* or */
strcpy(p->filename,"file1.txt");
depending on how you allocated the structure in the first place.
If you really wanted a list of filenames, then you may want char *filenames[64], but you will have to allocate a buffer for each name before you can use it
c.filenames[0] = malloc(sizeOfString);
/* error checking */
strcpy(c.filenames[0],...
or as another poster suggested
c.filenames[o] = strdup(...
The first form may be better if you are building your filenames from multiple pieces and can project the total length from the get go.
{*} Later you may want to scrap this fixed length buffer, but leave that for now.
It is currently failing because you aren't allocating memory for the filenames. Either use strdup or malloc+strcpy (I'd use strdup).
Your filename field is an array of pointers to zero terminated string. You need to allocate the memory for the string and copy the string to that memory. You save the address of the new string in one of the pointers, e.g. filename[0].
The direct memory address code doesn't work. It just doesn't crash, yet! That code just overwrites the array of pointers. Don't ever write code like that. Never ever ever!! Writing code like that is morally equivalent to eating baby unicorns.