Moving some code from sprintf to snprintf -
stumbled accross this weird occurence:
sprintf(buf+strlen(buf), "ypasZ%c%c", iItem, val);
I'm not understanding what is going on there: http://www.cplusplus.com/reference/cstdio/sprintf/ is not helping.
Is the first argument (the write to location) being "incremented" by its size?
=> does that mean the location being written isn't buf but is buf incremented by its size?
Or is it pre-setting the position of the write block to that of the existing string in buf, so as to APPEND the text?
Yes, it appends. The first argument to sprintf is the address (pointer) where it will write the result.
If buf is a char array, the compiler (in cases like this) will treat it like a pointer. And adding to it will increase the address. Adding the length what is there will point to the current end of the string.
Essentially the first parameter says address of string plus length of string that is there, giving the address of the end of the string, rather than the beginning, so the sprintf command will write its result right to the end of the current string.
Or is it pre-setting the position of the write block to that of the existing string in buf, so as to APPEND the text?
Yes, that's what it's doing.
The first argument is a pointer to an area where sprintf should write the formatted string. buf + strlen(buf) means address of the terminating NULL-character ('\0'). sprintf just writes into memory starting from that NULL-character thus continuing the string in buf.
What this means is that buf is probably defined as an array of size n, char buf[n]. Use of strlen(buf) is necessary because it would then return a pointer to the end of the string in buf, thus appending to it.
Related
Why is this happening?:
char buf[256];
char date[8];
sprintf(date, "%d%02d%02d", Time.year(), Time.month(), Time.day());
snprintf(buf, sizeof(buf), "{\"team\":\"%s\"}", team.c_str());
Serial.println(date);
output:
20180202{"team":"IND"}
it should only be: 20180202
I don't know why {"team":"IND"} is getting added to the end of it.
Very likely you declared two arrays and they are lined up in a way that allowed for the buf to overwrite the null terminator of date and thus it's "concatenating" the two.
I can't write code to reproduce this because it's undefined behavior and thus not reliable. But I can tell you how you can avoid it,
snprintf(date, sizeof(date), "%d%02d%02d", Time.year(), Time.month(), Time.day());
snprintf(buf, sizeof(buf), "{\"team\":\"%s\"}", team.c_str());
Having said that, why are you using snprintf() when this appears to be c++? And so there are more suitable solutions for this kind of problem.
This would print an incorrect value, but would not cause any unexpected behavior.
Strings in c are simply arrays with a special arrangement. If the string has n printable characters it should be stored in an array of size n + 1, so that you can add what is called a null terminator. It's a special value that indicates the end of the string.
Your second snprintf() is overwriting such null terminator of the date array and thus appearing to concatenate both strings.
You have reserved space to store exactly 8 chars:
char date[8];
To store the date properly 20180202 you need
char date[9];
because sprintf() puts the extra '\0' character to the buffer you pass for proper c-style string termination.
I'd suspect you declared your buffers like
char buffer[???];
char date[8];
since these are most likely stored on your processors stack, you need to read that backwards, thus the output placed at buffer overwrites that terminating '\0', and appears immediately after date.
I have create these simple function.
char* tmp = new char[len];
strncpy(tmp,str+start,len);
int ret = atoi(tmp);
delete []tmp;
return ret;
I have a problem with memory managment.
When I read ret variable, the value is null. If I remove the instruction "delete []tmp;" the value is correct but the memory fast increase (because I don't release the memory).
Any ideas?
Thanks
From man strncpy: The strncpy() function is similar than strcpy, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
Check your str variable length and verify this null terminating condicion on strncpy
There are a few problems with atoi, one of them is that it doesn't have any kind of validation that the string you pass is really a number. Instead you might want to use strtol instead.
Also note that strncpy might not terminate the string in some cases. And that you might want to allocate one extra character (len + 1) for the terminator.
strncpy fills up the target array with '\0's once the end of the source is reached.
atoi expects a null terminated c-string, means an array of characters that ends with a '\0'.
Therefore you have to create an array with a size of len + 1, the strncpy function will the automatically null-terminate your target array.
What you could do is have the buffer be allocated from outside the function, and pass the tmp argument as an array. A better approach though, is to allocate an object. These get destructed as long as you don't use the new keyword. std::string would be perfect in this scenario.
Make sure tmp is terminated with a '\0'
Hard to tell what's wrong since str and len are not shown.
This function could be a lot simpler:
int ret = atoi(str + start);
return ret;
BTW, ret is an int and NULL is usually referred to pointers.
Consider a simple example
Eg: const char* letter = "hi how r u";
letter is a const character pointer, which points to the string "hi how r u". Now when i want to print the data or to access the data I should use *letter correct?
But in this situation, shouldn't I only have to use the address in the call to printf?
printf("%s",letter);
So why is this?
*letter is actually a character; it's the first character that letter points to. If you're operating on a whole string of characters, then by convention, functions will look at that character, and the next one, etc, until they see a zero ('\0') byte.
In general, if you have a pointer to a bunch of elements (i.e., an array), then the pointer points to the first element, and somehow any code operating on that bunch of elements needs to know how many there are. For char*, there's the zero convention; for other kinds of arrays, you often have to pass the length as another parameter.
Simply because printf has a signature like this: int printf(const char* format, ...); which means it is expecting pointer(s) to a char table, which it will internally dereference.
letter does not point to the string as a whole, but to the first character of the string, hence a char pointer.
When you dereference the pointer (with *) then you are referring to the first character of the string.
however a single character is much use to prinf (when print a string) so it instead takes the pointer to the first element and increments it's value printing out the dereference values until the null character is found '\0'.
As this is a C++ question it is also important to note that you should really store strings as the safe encapulated type std::string and you the type safe iostreams where possible:
std::string line="hi how r u";
std::cout << line << std::endl;
%s prints up to the first \0 see: http://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx, %s is a character string format field, there is nothing strange going on here.
printf("%s") expect the address in order to go through the memory searching for NULL (\0) = end of string. In this case you say only letter. To printf("%c") would expect the value not the address: printf("%c", *letter);
printf takes pointers to data arrays as arguments. So, if you're displaying a string (a type of array) with %s or a number with %d, %e, %f, etc, always pass the variable name without the *. The variable name is the pointer to the first element of the array, and printf will print each element of the array by using simple pointer arithmetic according to the type (char is 1 or 2 bytes, ints are 4, etc) until it reaches an EOL or zero value.
Of course, if you make a pointer to the array variable, then you'd want to dereference that pointer with *. But that's more the exception than the rule. :)
I start of with a
memcpy(g->db_cmd,l->db.param_value.val,l->db.param_value.len);
which contains the value "function" however I want a null character to be appended like "function'\0'" I've tried a
memcpy(&g->db_cmd[l->db.param_value.len],0,1);
This crashes the program. I've tried memset also
memset(&g->db_cmd[l->db.param_value.len],0,1);
This doesnt work. Any idea?
g->db_cmd[l->db.param_value.len] = 0;
assuming you have allocated space for that.
First off, C (and C++) is not dynamic like you know it from Java, C#, PHP and others. When you are presented with a string in C, the string is pretty much static in length.
To make the answer simpler, lets redefine your variables:
g->db_cmd will be called dest,
l->db.param_value.val will be called src, and
l->db.param_value.len will be called len.
You should allocate a new string of size len plus one (for the extra null).
Allocate a new dest:
dest = calloc(sizeof(char), len + 1);
calloc allocates an array of chars as long as len plus one. After calloc() has allocated the array it fills it with nulls (or \0) thus you automatically will have a null appended to your deststring.
Next, copy the src to dest with strncpy:
strncpy(dest, src, len);
To convert this back to your variable names:
g->db_cmd = calloc(sizeof(char), l->db.param_value.len + 1);
strncpy(g->db_cmd, l->db.param_value.val, l->db.param_value.len);
If you want string-copying semantics, why not use a string-copying function?
Strings are by default null-terminated.
If you want a to ad an extra NULL at the end you can write "String\0"
or db_cmd[len]='\0'
If the source you're copying from also contains a NULL terminated string use
memcpy( g->db_cmd, l->db.param_value.val, l->db.param_value.len + 1 );
Otherwise you'll have to add the terminator yourself.
g->db_cmd[l->db.param_value.len] = '\0';
Of course, you need to ensure that the destination has enough room for this character.
memcpy takes two pointers, and an integer. In the lines that you say are crashing, you pass it a pointer, and two integers. The code cannot dereference the second argument (0).
If you really really want to use memcpy, you have to have a pointer to a zero
char zero = 0;
memcpy(&g->db_cmd[l->db.param_value.len], &zero , 1);
But I would really suggest pyroscope's answer. It's faster, and clearer.
std::strlen doesn't handle c strings that are not \0 terminated. Is there a safe version of it?
PS I know that in c++ std::string should be used instead of c strings, but in this case my string is stored in a shared memory.
EDIT
Ok, I need to add some explanation.
My application is getting a string from a shared memory (which is of some length), therefore it could be represented as an array of characters. If there is a bug in the library writing this string, then the string would not be zero terminated, and the strlen could fail.
You've added that the string is in shared memory. That's guaranteed readable, and of fixed size. You can therefore use size_t MaxPossibleSize = startOfSharedMemory + sizeOfSharedMemory - input; strnlen(input, MaxPossibleSize) (mind the extra n in strnlen).
This will return MaxPossibleSize if there's no \0 in the shared memory following input, or the string length if there is. (The maximal possible string length is of course MaxPossibleSize-1, in case the last byte of shared memory is the first \0)
C strings that are not null-terminated are not C strings, they are simply arrays of characters, and there is no way of finding their length.
If you define a c-string as
char* cowSays = "moo";
then you autmagically get the '\0' at the end and strlen would return 3. If you define it like:
char iDoThis[1024] = {0};
you get an empty buffer (and array of characters, all of which are null characters). You can then fill it with what you like as long as you don't over-run the buffer length. At the start strlen would return 0, and once you have written something you would also get the correct number from strlen.
You could also do this:
char uhoh[100];
int len = strlen(uhoh);
but that would be bad, because you have no idea what is in that array. It could hit a null character you might not. The point is that the null character is the defined standard manner to declare that the string is finished.
Not having a null character means by definition that the string is not finished. Changing that will break the paradigm of how the string works. What you want to do is make up your own rules. C++ will let you do that, but you will have to write a lot of code yourself.
EDIT
From your newly added info, what you want to do is loop over the array and check for the null character by hand. You should also do some validation if you are expecting ASCII characters only (especially if you are expecting alpha-numeric characters). This assumes that you know the maximum size.
If you do not need to validate the content of the string then you could use one of the strnlen family of functions:
http://msdn.microsoft.com/en-us/library/z50ty2zh%28v=vs.80%29.aspx
http://linux.about.com/library/cmd/blcmdl3_strnlen.htm
size_t safe_strlen(const char *str, size_t max_len)
{
const char * end = (const char *)memchr(str, '\0', max_len);
if (end == NULL)
return max_len;
else
return end - str;
}
Yes, since C11:
size_t strnlen_s( const char *str, size_t strsz );
Located in <string.h>
Get a better library, or verify the one you have - if you can't trust you library to do what it says it will, then how the h%^&l do you expect your program to?
Thats said, Assuming you know the length of the buiffer the string resides, what about
buffer[-1+sizeof(buffer)]=0 ;
x = strlen(buffer) ;
make buffer bigger than needed and you can then test the lib.
assert(x<-1+sizeof(buffer));
C11 includes "safe" functions such as strnlen_s. strnlen_s takes an extra maximum length argument (a size_t). This argument is returned if a null character isn't found after checking that many characters. It also returns the second argument if a null pointer is provided.
size_t strnlen_s(const char *, size_t);
While part of C11, it is recommended that you check that your compiler supports these bounds-checking "safe" functions via its definition of __STDC_LIB_EXT1__. Furthermore, a user must also set another macro, __STDC_WANT_LIB_EXT1__, to 1, before including string.h, if they intend to use such functions. See here for some Stack Overflow commentary on the origins of these functions, and here for C++ documentation.
GCC and Clang also support the POSIX function strnlen, and provide it within string.h. Microsoft too provide strnlen which can also be found within string.h.
You will need to encode your string. For example:
struct string
{
size_t len;
char *data;
} __attribute__(packed);
You can then accept any array of characters if you know the first sizeof(size_t) bytes of the shared memory location is the size of the char array. It gets tricky when you want to chain arrays this way.
It's better to trust your other end to terminate it's strings or roll your own strlen that does not go outside the bounderies of the shared memory segment (providing you know at least the size of that segment).
If you need to get the size of shared memory, try to use
// get memory size
struct shmid_ds shm_info;
size_t shm_size;
int shm_rc;
if((shm_rc = shmctl(shmid, IPC_STAT, &shm_info)) < 0)
exit(101);
shm_size = shm_info.shm_segsz;
Instead of using strlen you can use shm_size - 1 if you are sure that it is null terminated. Otherwise you can null terminate it by data[shm_size - 1] = '\0'; then use strlen(data);
a simple solution:
buff[BUFF_SIZE -1] = '\0'
ofc this will not tell you if the string originally was exactly BUFF_SIZE-1 long or it was just not terminated... so you need xtra logic for that.
How about this portable nugget:
int safeStrlen(char *buf, int max)
{
int i;
for(i=0;buf[i] && i<max; i++){};
return i;
}
As Neil Butterworth already said in his answer above: C-Strings which are not terminated by a \0 character, are no C-Strings!
The only chance you do have is to write an immutable Adaptor or something which creates a valid copy of the C-String with a \0 terminating character. Of course, if the input is wrong and there is an C-String defined like:
char cstring[3] = {'1','2','3'};
will indeed result in unexpected behavior, because there can be something like 123#4x\0 in the memory now. So the result of of strlen() for example is now 6 and not 3 as expected.
The following approach shows how to create a safe C-String in any case:
char *createSafeCString(char cStringToCheck[]) {
//Cast size_t to integer
int size = static_cast<int>(strlen(cStringToCheck)) ;
//Initialize new array out of the stack of the method
char *pszCString = new char[size + 1];
//Copy data from one char array to the new
strncpy(pszCString, cStringToCheck, size);
//set last character to the \0 termination character
pszCString[size] = '\0';
return pszCString;
}
This ensures that if you manipulate the C-String to not write on the memory of something else.
But this is not what you wanted. I know, but there is no other way to achieve the length of a char array without termination. This isn't even an approach. It just ensures that even if the User (or Dev) is inserting ***** to work fine.