I need to pass a char * to a function, but this function really needs const?
But I'm reading it from file and it's dynamic for me:
fseek(fcode, 0, SEEK_END);
i=ftell(fcode);
square_scm = (char*) malloc(i);
//free(square_scm);
fseek(fcode, 0, SEEK_SET);
fread(square_scm, 1, i, fcode);
scheme_load_string(sc, square_scm);
So square_scm here is:
"(display
(string-append "Answer: "
(number->string (square 6.480740698407859)) "\n"))юоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюоюо"
without free :
"(display
(string-append "Answer: "
(number->string (square 6.480740698407859)) "\n"))ННээээ««««««««««««««««ю"
How can I make it like char[size], like:
"(display
(string-append "Answer: "
(number->string (square 6.480740698407859)) "\n"))"
?
Your free() is a disaster; you only free() the data when you've finished with it.
You should probably be error checking the return codes, at least of malloc() and fread().
The data read from the file will not be null terminated. You need to over-allocate by one byte and add the terminal NUL ('\0') after reading the data into your allocated buffer. (Note that the file might have shrunk since you opened it; pay attention to the value returned from fread(). If the file grew, you won't see the extra data, but no other damage will occur.)
You ask about const. Presumably the function square_cm() has a signature such as:
void square_cm(SomeType *sc, const char *data_string);
and you are worried that you have a char * and not a const char * in your calling code?
You do not need to be concerned; the compiler will 'add const' for you. The const is actually a promise to you, the user of the function, that the function itself will not modify your data. It can take a fixed string (eg a string constant) or a dynamically allocated string, and it doesn't matter. Where you run into problems is when you have a const char * or a string literal that you need to pass to a function that takes a char *. Here the function does not self-evidently promise to leave the string alone, which can cause problems. For example, you can't pass a string literal to strtok() because the function tries to modify the string, but the string is probably in read-only memory, which triggers problems (core dumps on Unix; undefined behaviour everywhere).
So, const in a function signature is a promise to the consumer (user) of the function not to change something. You can pass const or non-const data to that function because it won't be modified either way.
You are using a freed pointer, which causes undefined behaviour. You should delete or move the free() call.
You aren't null terminating the string after you read it from the file. You should null terminate that string. Something like:
square_scm[i] = 0;
Make sure the you have allocated enough space to allow for the null terminator - that means adding a +1 to your malloc() call.
Alternately, you can add a maximum field width to your printf() call:
printf("%*s", i, string);
Though you haven't shown the code where the printing happens, so that may or may not be practical.
You should probably also do some error checking.
Don't free the malloced memory until you are done with it. And to answer your question, always leave space for the terminating null byte in the strings and do set the last byte to null byte.
fseek(fcode, 0, SEEK_END);
i=ftell(fcode);
//allocate for null byte too
square_scm = malloc(i + 1);
//reset the memory before using it
memset(square_scm, 0, i + 1);
fseek(fcode, 0, SEEK_SET);
fread(square_scm, 1, i, fcode);
square_scm[i] = 0; //not really required as we have already memset it
scheme_load_string(sc, square_scm);
//now you should free it, assuming it is not used anymore
free(square_scm);
Related
I am trying to use the C's strtok function in order to process a char* and print it in a display, and looks like that for some reason I don't know the character '\n' is not substituted by '\0' as I believe strtok does. The code is as follows:
-Declaration of char* and pass to the function where it will be processed:
char *string_to_write = "Some text\nSome other text\nNewtext";
malloc(sizeof string_to_write);
screen_write(string_to_write,ALIGN_LEFT_TOP,I2C0);
-Processing of char* in function:
void screen_write(char *string_to_write,short alignment,short I2C)
{
char *stw;
stw = string_to_write;
char* text_to_send;
text_to_send=strtok(stw,"\n");
while(text_to_send != NULL)
{
write_text(text_to_send,I2C);
text_to_send=strtok(NULL, "\n");
}
}
When applying the code, the result can be seen in imgur (Sorry, I am having problems with format adding the image here in the post), where it can be seen that the \n is not substituted as it is the strange character appearing in the image, and the debugger still showed the character as well. Any hints of where can the problem be?
Thanks for your help,
Javier
strtok expects to be able to mutate the string you pass it: instead of allocating new memory for each token, it puts \0 characters into the string at token boundaries, then returns a series of pointers into that string.
But in this case, your string is immutable: it's a constant stored in your program, and can't be changed. So strtok is doing its best: it's returning indices into the string for each token's starting point, but it can't insert the \0s to mark the ends. Your device can't handle \ns in the way you'd expect, so it displays them with that error character instead. (Which is presumably why you're using this code in the first place.)
The key is to pass in only mutable strings. To define a mutable string with a literal value, you need char my_string[] = "..."; rather than char* my_string = "...". In the latter case, it just gives you a pointer to some constant memory; in the former case, it actually makes an array for you to use. Alternately, you can use strlen to find out how long the string is, malloc some memory for it, then strcpy it over.
P.S. I'm concerned by your malloc: you're not saving the memory it gives you anywhere, and you're not doing anything with it. Be sure you know what you're doing before working with dynamic memory allocation! C is not friendly about that, and it's easy to start leaking without realizing it.
1.
malloc(sizeof string_to_write); - it allocates the sizeof(char *) bytes not as many bytes as your string needs. You also do not assign the allocated block to anything
2.
char *string_to_write = "Some text\nSome other text\nNewtext";
char *ptr;
ptr = malloc(strlen(string_to_write) + 1);
strcpy(ptr, string_to_write);
screen_write(ptr,ALIGN_LEFT_TOP,I2C0);
Can I free a pointer such as:
unsigned char *string1=NULL;
string1=malloc(4096);
After altering its value like:
*string1+=2;
Can free(string1) recognize the corresponding memory block to free after incrementing it (for example to point to a portion of a string), or do I need to keep the original pointer value for freeing purposes?
For example, for an implementation of the Visual Basic 6 function LTrim in C, I need to pass **string as a parameter, but in the end I will return *string+=string_offset_pointer to start beyond any blank spaces/tabs.
I think that here I am altering the pointer so if I do this in this way I will need to keep a copy of the original pointer to free it. It will probably be better to overwrite the non-blank contents into the string itself and then terminate it with 0 to avoid requiring an additional copy of the pointer just to free the memory:
void LTrim(unsigned char **string)
{
unsigned long string_length;
unsigned long string_offset_pointer=0;
if(*string==NULL)return;
string_length=strlen(*string);
if(string_length==0)return;
while(string_offset_pointer<string_length)
{
if(
*(*string+string_offset_pointer)!=' ' &&
*(*string+string_offset_pointer)!='\t'
)
{
break;
}
string_offset_pointer++;
}
*string+=string_offset_pointer;
}
It would probably be best to make the function to overwrite the string with a substring of it but without altering the actual value of the pointer to avoid requiring two copies of it:
void LTrim(unsigned char **string)
{
unsigned long string_length;
unsigned long string_offset_pointer=0;
unsigned long string_offset_rebase=0;
if(*string==NULL)return;
string_length=strlen(*string);
if(string_length==0)return;
//Detect the first leftmost non-blank
//character:
///
while(string_offset_pointer<string_length)
{
if(
*(*string+string_offset_pointer)!=' ' &&
*(*string+string_offset_pointer)!='\t'
)
{
break;
}
string_offset_pointer++;
}
//Copy the non-blank spaces over the
//originally blank spaces at the beginning
//of the string, from the first non-blank
//character up to the string length:
///
while(string_offset_pointer<string_length)
{
*(*string+string_offset_rebase)=
*(*string+string_offset_pointer);
string_offset_rebase++;
string_offset_pointer++;
}
//Terminate the newly-copied substring
//with a null byte for an ASCIIZ string.
//If the string was fully blank we will
//just get an empty string:
///
*(*string+string_offset_rebase)=0;
//Free the now unused part of the
//string. It assumes that realloc()
//will keep the current contents of our
//memory buffers and will just truncate them,
//like in this case where we are requesting
//to shrink the buffer:
///
realloc(*string,strlen(*string)+1);
}
Since you're actually doing
unsigned char *string1=NULL;
string1=malloc(4096);
*string1+=2;
free(string1);
free(string1) IS being passed the result of a malloc() call.
The *string1 += 2 will - regardless of the call of free() - have undefined behaviour if string1[0] is uninitialised. (i.e. If there is some operation that initialises string1[0] between the second and third lines above, the behaviour is perfectly well defined).
If the asterisk is removed from *string1 += 2 to form a statement string1 += 2 then the call of free() will have undefined behaviour. It is necessary for free() to be passed a value that was returned by malloc() (or calloc() or realloc()) that has not otherwise been deallocated.
The value passed to free() must be a pointer returned by malloc(), calloc(), or realloc(). Any other value results in undefined behavior.
So you have to save the original pointer if you modify it. In your code you don't actually modify the pointer, you just increment the contents of the location that it points to, so you don't have that problem.
Why is the language specified this way, you might ask? It allows for very efficient implementations. A common design is to store the size allocation in the memory locations just before the data. So the implementation of free() simply reads the memory before that address to determine how much to reclaim. If you give some other address, there's no way for it to know that this is in the middle of an allocation and it needs to scan back to the beginning to find the information.
A more complicated design would keep a list of all the allocations, and then determine which one the address points into. But this would use more memory and would be much less efficient, since it would have to search for the containing allocation.
I have the following test function to copy and concatenate a variable number of string arguments, allocating automatically:
char *copycat(char *first, ...) {
va_list vl;
va_start(vl, first);
char *result = (char *) malloc(strlen(first) + 1);
char *next;
strcpy(result, first);
while (next = va_arg(vl, char *)) {
result = (char *) realloc(result, strlen(result) + strlen(next) + 1);
strcat(result, next);
}
return result;
}
Problem is, if I do this:
puts(copycat("herp", "derp", "hurr", "durr"));
it should print out a 16-byte string, "herpderphurrdurr". Instead, it prints out a 42-byte string, which is the correct 16 bytes plus 26 more bytes of junk characters.
I'm not quite sure why yet. Any ideas?
The variable-argument-list functions don't magically know how many arguments there are, so you're most likely walking the stack until you happen to hit a NULL.
You either need an argument numStrings, or supply an explicit null-terminator argument after your list of strings.
You need a sentinel marker on your list:
puts(copycat("herp", "derp", "hurr", "durr", NULL));
Otherwise, va_arg doesn't actually know when to stop. That fact that you're getting junk is pure accident since you're invoking undefined behaviour. For example, when I ran your code as-is, I got a segmentation fault.
Variable argument functions, such as printf need some sort of indication as to how many items are passed in: printf itself uses the format string up front to figure this out.
The two general methods are a count (or format string) which is useful when you can't use one of the possible values as a sentinel (a marker at the end).
If you can use a sentinel (like NULL in the case of pointers, or -1 in the case of non-negative signed integers, that's usually better so you don't have to count the elements (and possible get the element count and element list out of step).
Keep in mind that puts(copycat("herp", "derp", "hurr", "durr")); is a memory leak since you're allocating memory then losing the pointer to it. Using:
char *s = copycat("herp", "derp", "hurr", "durr");
puts(s);
free (s);
is one way to fix that, and you may want to put in error checking code in case the allocations fail.
What I understand from your code is that you assume va_next will return NULL once each argument has been "popped". That's wrong as va_next has absolutely no way to determine the number of arguments : your while loop will keep running until a NULL is randomly hit.
Solution : either provide the number of arguments, or add call your function with an additional "NULL" argument.
PS: if you are wondering why printf doesn't require such an additional argument, it's because the number of expected arguments is deduced from the format string (the number of '%flag')
As an addition to the other answers, you should cast the NULL to the expected type when using it as an argument to a variadic function: (char *)NULL. If NULL is defined as 0, then an int will be stored instead, which will accidentally work when int has the sime size as the pointer and NULL is represented by all bits 0. But none of this is guaranteed, so you may run into strange behaviour that's hard to debug when porting the code or even when only changing the compiler.
As others have mentioned, va_arg does not know when to stop. It is up to you to provide NULL (or some other marker) when you call the function. Just a few side notes:
You must call free on pointers you obtain from malloc and realloc.
There is no reason to cast the result of malloc or realloc in C.
When calling realloc, it is best to store the return value into a temporary variable. If realloc is unable to reallocate enough memory, it returns NULL but the original pointer is not freed. If you use realloc the way you do, and it is unable to reallocate the memory, then you have lost the original pointer and your subsequent call to strcat will likely fail. You could use it like this:
char *tmp = realloc(result, strlen(result) + strlen(next) + 1);
if (tmp == NULL)
{
// handle error here and free the memory
free(result);
}
else
{
// reallocation was successful, re-assign the original pointer
result = tmp;
}
Given:
char test[] = "bla-bla-bla";
Which of the two is more correct?
char *test1 = malloc(strlen(test));
strcpy(test1, test);
or
char *test1 = malloc(sizeof(test));
strcpy(test1, test);
This will work on all null-terminated strings, including pointers to char arrays:
char test[] = "bla-bla-bla";
char *test1 = malloc(strlen(test) + 1);
strcpy(test1, test);
You won't get the correct size of the array pointed to by char* or const char* with sizeof. This solution is therefore more versatile.
Neither:
#include <string.h>
char *mine = strdup(test);
You should use strlen, because sizeof will fail silently if you change test to be a run-time defined string. This means that strlen is a far safer idea than sizeof as it will keep working.
char test[]="bla-bla-bla";
char *test1 = malloc(strlen(test) + 1); // +1 for the extra NULL character
strcpy(test1, test);
I think sizeof is the correct one. Reason behind that is strlen(str) will give you length of the string( excluding the terminating null). And if you are using strcpy, it actually copy the whole string including the terminating null, so you will allocate one byte less if you use strlen in malloc. But sizeof gives the size of the string pointed by test, including the terminating null, so you will get correct size malloc chunk to copy the string including the terminating null.
1) definitely causes UB
2) may cause UB (if malloc fails)
I'd go with 2) as there is a better chance of the construct working as intended; or even better I'd write a version that works as intended (without UB) in all situations.
Edit
Undefined Behaviour in 1)
test1 will have space for the characters in test, but not for the terminating '\0'. The call to strcpy() will try to write a '\0' to memory that does not belong to test1, hence UB.
Undefined Behaviour in 2)
If the call to malloc() fails to reserve the requested memory, test1 will be assigned NULL. Passing NULL to strcpy() invokes UB.
The return value of calls to malloc() (and calloc() and friends) should always be tested to ensure the operation worked as expected.
(1) with strlen but not adding 1 is definitely incorrect. If you add 1, it would have the added benefit that it also works for pointers, not just arrays.
On the other hand, (2) is preferred as long as your string is actually an array, as it results in a compile-time constant, rather than a call to strlen (and thus faster and smaller code). Actually a modern compiler like gcc can probably optimize the strlen out if it knows the string is constant, but it may be hard for the compiler to determine this, so I'd always use sizeof when possible.
If it is a critical path, sizeof has advantage over strlen as it has an O(1) complexity which can save CPU cycles.
I do something like that in the loop :
char* test = "\0";
test = strcat(test, somestr);
...
char* tmp = strstr(test, 0, len);
free(test);
test = tmp;
And get memory leak. What I do wrong?
You don't actually have a memory leak (in the code you posted anyway), but you do several things wrong.
char* test = "\0";
This declares pointer named test and initializes it to point to some literal array of two bytes { 0, 0 }
test = strcat(test, somestr);
This tries to append something to the end of that string literal (and since as a C string it is empty it would be like a string copy). Literal values often are stored in memory that is not writable, so copying something into this memory would likely cause an error (segmentation fault or SIGSEGV on many operating systems). Additionally you only have two bytes of storage pointed to by test, which means that unless somestr refers to a string whose strlen is less than or equal to 1 you would end up attempting to write over some other memory (whatever happens to be after the "\0" that test points to).
char* tmp = strstr(test, 0, len);
I don't know what is going on here since strstr only takes 2 arguments (both of them const char *).
free(test);
Here you are attempting to free non-heap allocated memory. The heap is where malloc, realloc, and calloc get the memory they allocate. Calling free with a memory location that was not returned by one of these functions (and a few other functions on some systems) is an error because free does not know what to do with them.
You should probably keep in mind that often memory is huge array of bytes, and that the pointers you use are like array indexes. The system you are using may be able to distinguish between some areas of this array and determine how you can access them (readable, writable, and/or executable). But it is still just an array of bytes. When you have a string (such as "foo") that means that somewhere in RAM there are four bytes ( 3 letters + the \0 terminator byte) and you can access this area by knowing its index within the array of bytes that is RAM. There are likely other things that are stored adjacent to your string (such as { ..., 4, 2, 'f', 'o', 'o', 0, 99, 3, 2, ...}) so you have to try to make sure you stay within the space of that memory without wandering into the adjacent data.
There are a couple of problems:
strcat will append a string to the destination buffer. You need the first parameter to be a buffer not a string literal pointer. Here is an example of a char buffer or also called an array of chars: char test[1024];
The return value of strcat is a pointer to the destination buffer, it is not a newly allocated string on the heap. So you shouldn't call free on the return value.
You can't strcat to test because you are initially pointing it to a constant char *. You need to assign memory for it. strcat won't do it.
Change your code to something like:
char* test = (char*)malloc(20*sizeof(char));
test[0] = '\0'; // nothing on this string to begin with
strcat(test, "something");
free(test);
Also, this won't work:
char* tmp = strcat(test, 0, len);
Since there is no strcat function with three parameters.
Remember. 99.9% of the time there will be a free call for each malloc allocation.