I'm having some issue with my stack implementation, my push function manipulate the value i send into the function and changes it. I have tried diffrent ways of constructing this but they either don't work or give me corrupted output.
The base idea is the one below here, note: my pop function only walks down one position and doesn't free the memory at the specific position. I can not use strcpy since im working with threads.
Does strdup change the value that it copies, i cant find any information saying that is the case, my understanding is that you are suppose to be able to use the value after it has ben duped.
And how is the correct way to use strdup on a already allocated memory space, i assume that i can't just free it and then use it again.
void stack_push(Stack *s, char *value)
{
if (s->size == s->capacity) {
realloc_stack(s);
}
if(s->data[s->size] == NULL){
// The current position does not contain any data.
s->data[s->size] = strdup(value);
}
else{
free(s->data[s->size]);
s->data[s->size] = strndup(value, strlen(value) + 1);
}
s->size += 1;
}
Edit s->data = char **data
strdup is basically this (no error checking for brevity):
char *strdup(const char *stringtoduplicate)
{
char *newstring = malloc(strlen(stringtoduplicate) + 1);
strcpy(newstring, stringtoduplicate);
return newstring;
}
You use it like this:
char Foo[] = "Bar";
char *newBar = strdup(Foo);
Foo[0] = 'F';
printf("%s %s\n", Foo, newBar); // prints: Far Bar
...
free(newBar); // once you're done with newBar, free it
Now you should be able to answer your own question.
strdup does not in any way modify its argument. If you look at the prototype for strdup you will see that its parameter is declared const, which means that it is not modified.
strdup can be implemented as:
char* strdup(const char* s) {
char* n = malloc(strlen(s) + 1);
if (n) strcpy(n, s);
return n;
}
There is no magic.
You can use strcpy with threads, by the way. But strdup works fine.
Related
I'm having a little problem with a (pretty big) c program and figured out that the problem does not come from my program itself but the way I create my array, I think.
My problem is the following, I need to create an array who's identical to the one containing environment variables (extern char **environ) and then add another value at the end.
Here is a code that I've done to check if the environ is well copied or not:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int ft_length(char **arr)
{
int i = 0;
while (arr[i])
i++;
return (i);
}
int main(void)
{
extern char **environ;
char **env;
int err;
int x;
err = 0;
x = 0;
env = (char**)malloc(sizeof(char*) * ft_length(environ) + 2);
while (environ[x])
{
// printf("%s\n", environ[x]);
env[x] = (char*)malloc(sizeof(char) * strlen(environ[x]) + 1);
bzero(env[x], strlen(environ[x]));
strncpy(env[x], environ[x], strlen(environ[x]));
// printf("%s\n", env[x]);
x++;
}
env[x] = (char*)malloc(sizeof(char) * 4);
env[x] = "ccc\0";
env[++x] = NULL;
x = 0;
while (environ[x])
{
if (strcmp(environ[x], env[x]) != 0)
{
err++;
printf("error on env[%d]\n", x);
printf("environ[%d] : |%s|\n", x, environ[x]);
printf("env[%d] : |%s|\n", x, env[x]);
printf("----------------\n");
}
x++;
}
while (env[x])
{
if (strcmp(env[x], "ccc") != 0)
{
err++;
printf("env[%d] contain |%s| instead of |ccc|\n", x, env[x]);
}
x++;
}
printf("done with %d error(s)\n", err);
return (1);
}
When I run this code on Mac OSX, env[0] is empty at the end, and that happen when I set the last array value to NULL (env[++x] = NULL). But, well, I need this one to be NULL if I want to print my array without segfault.
So, first I wanted to know if my code is wrong somewhere?
I tried to run this code on my Linux computer (Ubuntu 16.04) too and it seems there is no problem.
malloc(sizeof(char*) * ft_length(environ) + 2)
If you need two additional elements in the array, that'd be
malloc(sizeof(char*) * (ft_length(environ) + 2));
Or use calloc:
calloc (ft_length(environ) + 2, sizeof(char*));
In addition
env[x] = (char*)malloc(sizeof(char) * 4);
env[x] = "ccc\0";
is another pitfall everybody seems to fall in. You assign a pointer value to env[x], then immediately regret and assign another pointer value to it, forgetting the first one, creating a memory leak in process, and making your env impossible to free as the new string is not pointing to a dynamically allocated memory. This is particularly baffling as you seem to correctly (even if with much redundancy) copy a string a few lines earlier.
env[x] = malloc(4); // sizeof(char) is always one; casting not needed
// also see below
strcpy (env[x], "ccc"); // of course no `\0` is needed
Since you have code that dynamically allocates a copy of a string in two places, you may want to make this code into a function, or perhaps use an existing (albeit non-standard) function strdup. This is particularly important because there's no good way to copy a string literal otherwise.
env[x] = malloc(4);
strcpy (env[x], "ccc");
Assumes the length. What if the literal will change?
env[x] = malloc(strlen("ccc")+1);
strcpy (env[x], "ccc");
What if someone changes one literal and forgets the other?
const char ccc[] = "ccc";
env[x] = malloc(sizeof(ccc));
strcpy (env[x], ccc);
This works but you have an extra line that declares a variable. This doesn't sound like much but why?
env[x] = strdup("ccc");
Looks better, maintains better.
If you write your own strdup don't do this
out = (char*)malloc(sizeof(char) * strlen(in) + 1);
bzero(out, strlen(in));
strncpy(out, in, strlen(in));
but rather
out = malloc(strlen(in) + 1);
strcpy(out, in);
bzero is redundant because it will zero out exactly the bytes that strcpy will overwrite with non-zero values at the next line. The strncpy + strlen combo is plain wrong as it doesn't null-terminate the destination string. strncpy(out, in, strlen(in)+1) would be correct but redundant, as it does exactly the same thing as plain strcpy(out, in).
I was asked to make 2 functions copyString and concatString i did and Implemented them both but at the output that i got תi have been told that it can be done better but never got explained how.
now it is killing me what could i do better so here is the code and i will be happy to hear any suggestions.
void copyString (char **strDst, const char *strSrc)
{
char *strTmp = NULL;
int length = strlen (src);
if (*strDst== NULL)
{
*strDst= malloc (length);
}
else
{
if (strlen(*strDst) != length)
{
strTmp = *strDst;
}
*strDst= malloc (length);
}
strcpy (*strDst, strSrc);
if (strTmp != NULL)
free (strTmp );
}
void concatString (char **strDst, const char *cat)
{
int cat_length = strlen (cat);
if (cat_length > 0)
{
*strDst= realloc (*strDst, strlen (*strDst) + cat_length);
strcat (*strDst, cat);
}
}
void main(int argc, char *argv[])
{
char *str = NULL;
copyString(&str, "Hello World");
puts(str);
copyString(&str,str+6);
puts(str);
concatString(&str, " Pesron");
}
The ouput should be as following:
1.Hello World
2. World
3. World Person
Thanks.
Errors:
strlen returns the length excluding the nul terminator, so all of your sizes that you allocate are too small.
In the case where if (strlen(*strDst) != length) is false, (that is, the lengths are equal) you leak the old buffer.
realloc and malloc can both fail, you should be able to write code to cope with that.
The correct way to use realloc is:
char *newbuf = realloc(oldbuf, newsize);
if (newbuf == NULL) {
// handle the error somehow, and note that oldbuf is still allocated
} else {
oldbuf = newbuf;
}
"Handle the error somehow" might require deciding what to do, depending on what the documentation of your two functions says they do on failure. If it doesn't say then it should.
(Picky) int is not guaranteed to be a large enough type to hold the length of a string. Use size_t (unless maybe you've been strictly forbidden from using unsigned types, in which case there's ssize_t).
Things you can improve:
There's no need to use strTmp the way you do, you could free the string immediately instead of at the end of the function. [Edit: yes there is a need, there seems to be a requirement that copyString but not concatString should permit overlap of source and destination. Personally I'd still write it slightly differently.]
In if (strTmp != NULL) free (strTmp ); the test is redundant since it is valid to call free with a null pointer, and doing so has no effect.
You do *strDst= malloc (length); in both cases in copyString.
main leaks memory since it never frees str.
main should return int, not void.
Here's how I might write them:
Since you can't change the calling code to make it check for error, you have to either abort() or else write something there that it can call puts on. Since the main function was written on the assumption that the calls cannot fail, abort() is probably the least bad solution.
It would probably be better for the caller if the functions return a value indicating success or failure, but we're constrained by the existing calling code. To be honest that's not a totally unrealistic situation to be programming for...
void concatString (char **strDst, const char *cat) {
size_t dstlen = *strDst ? strlen(*strDst) : 0;
char *buf = realloc(*strDst, dstlen + strlen(cat) + 1);
if (!buf) {
abort();
}
strcpy(buf + dstlen, cat);
*strDst = buf;
}
void copyString (char **strDst, const char *strSrc) {
char *buf = malloc(strlen(strSrc) + 1);
if (!buf) {
abort();
}
strcpy(buf, strSrc);
free(*strDst);
*strDst = buf;
}
Besides of what Steve Jessop mentions in his answer, no errors in your sources but missing:
validation of input parameters
return errors through error value (for example as integer return code of the function, instead of void
I have the following function which gets called multiple times in my code:
char* get_section_name(const char* section, const char* value) {
char *tmp = (char *)malloc(STR_LEN * sizeof(char));
if(strlen(section)>0) {
strcat(tmp, section);
strcat(tmp,".");
}
strcat(tmp, value);
return tmp;
}
and I call it in other functions like this:
section_name = get_section_name(data->model_name,"params_default");
What is the best way to free this memory? Can I just call free(section_name) when I am done?
Yes free, however, you could consider a different name that makes it clear it is allocating memory. Also, you could make use of sprintf for combining 2 strings and strdup for just copying one.
char* create_section_name(const char* section, const char* value) {
const int sectionLen = strlen(section);
if(sectionLen>0) {
//+1 for the period and +1 for the null
char *tmp = (char *)malloc((sectionLen + strlen(value) + 2) * sizeof(char));
//do that often? consider a newString(size) macro. See below
sprintf(tmp, "%s.%s", section, value);
return tmp;
}
else {
return strdup(value);
}
}
This assumes you don't need the full STR_LEN, it uses just enough in both cases.
newString macro I suggested:
#define newString(size) (malloc((size) * sizeof(char)))
Or it can even automatically add one for the null:
#define newString(size) (malloc(((size)+1) * sizeof(char)))
Then malloc is replaced with this:
char *tmp = newString(sectionLen + strlen(value) + 1); //+1 for period
First, you must make sure tmpwas actually allocated (ie mallocdid not fail) :
tmp = (char *)malloc(STR_LEN * sizeof(char));
if (tmp == NULL) {
// quit now !
}
Then, as you strcat it, you must be sure tmp is an empty string, ie its first character is 0
tmp[0] = '\0';
Then, yes, you can free it the way you wrote it.
One last thing : you have to be sure that strlen(section)+strlen(".")+strlen(value) < STR_LEN, or you will overwrite memory you're not supposed to.
free would be great here, but as an alternative, might be the best way to do this would be a change to signature. If you make it like
void get_section_name(const char* section, const char* value, char * result)
then you can pass a pointer to an allocated memory, so the user of this function is perfectly aware of how should he handle the memory after it's used.
Always perform error check when creating memory using malloc(),calloc(), orrealloc()
Yes you can use free here
free(section_name) , Because tmpreturned is stored in section_name which now points to malloced memory.
I am going to make a leap of faith that STR_LEN is going to be of sufficient size. If so then free(section_name); will suffice. Bur use strcpy instead of strcat or initialize a null string.
I have two functions, one that creates a pointer to a string and another that manipulates it. I somehow am missing something critical, however:
int foo() {
char * mystring; // Create pointer
bar(&mystring); // Pass in address
printf("%s\n", mystring);
return 0; // There's a reason for this
}
int bar(char ** mystring) {
mystring[0] = malloc(strlen(mystring) + 1); // Since malloc will persist even after exiting bar
*mystring = "hahaha"; // Dereference
return 0;
}
Any enlightenment for my addled brain would be greatly appreciated!
C doesn't have strings as first class values; you need to use strcpy() to assign strings.
strcpy(mystring[0], "hahaha");
In addition to the other answers given, note that:
mystring[0]
is the same as
*(mystring + 0)
which is the same as
*mystring
Your malloc allocates the memory and the pointer is written to mystring but it is overwritten by the next line.
The use of malloc is necessary, but this way:
mystring[0] = malloc(strlen(mystring) + 1);
is wrong, since you can't perform strlen on mystring(because it doesn't contain any string yet and because the pointer itself is not initialized). Allocate buffer with the size of your string. for example:
int bar(char ** mystring) {
char* hello = "hahaha";
*mystring = malloc(strlen(hello) + 1);
strcpy(*mystring, hello);
return 0;
}
BTW, you could use the assignment *mystring = "hahaha"; without the malloc since this is a string stored in the data section, and the data will not be lost after returning from the function, but this way it is read-only data and you cannot modify it. The strcpy is there to copy the string to the allocated buffer.
If i have char* str; how do I write a function that accepts str and can make changes to str so that, the changes persist after the function returns?
what I have is:
char *str = (char *) malloc(10);
sprintf(str, "%s", "123456789");
//str points to 1
move_ptr(&str);
//str points to 2
void move_ptr(char** str)
{
*str++;
}
is there a better way to do that?
Just access the data through the pointer, in the function:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
void change_string(char *str)
{
size_t i;
/* As an example, make it all upper case. */
for(i = 0; str[i]; ++i)
str[i] = toupper(str[i]);
}
int main(void)
{
char buffer[32];
char *str = buffer;
strcpy(str, "test string");
change_string(str);
printf("it's now %s\n", str);
return EXIT_SUCCESS;
}
Come to think of it, you'll notice that the standard strcpy() function is exactly of the category you describe. It's a very common operation in C.
UPDATED: The question has been significantly rewritten, now it seems to be more about changing the pointer itself, rather than the data. Perhaps this was the meaning all along, but I didn't understand.
The solution in the question is fine, but personally I find it more convenient to work with return values, if possible:
char * change_pointer(char *str)
{
return str + 1;
}
int main(void)
{
char *str = "test string";
printf("now '%s'\n", str);
str = change_pointer(str);
printf("now '%s'\n", str);
return EXIT_SUCCESS;
}
The pointer(s) could of course also be const-declared, and should be if no changes to the buffered text are needed.
Question changed
If your pointer points to readonly data, you can't change what it points to.
When one writes
char *data = "forty two";
that "forty two" is readonly data; and you can't change what the pointer data points to whether directly or through a function call.
To get a 'string' initialized from a literal constant, instead of assigning a pointer to the literal constant, copy the characters to an array
char data[] = "forty two";
Now data is an array of 10 characters (9 for the letters and space + 1 for the NUL terminator) which you can change at will.
Your example may be over simplified, but just in case... Be careful of doing things like this because you're going to leak memory. After your function call, you no longer have a pointer to (part of) the original memory you allocated.
As mentioned by unwind, returning the new pointer may be a better choice. While it achieves the same goal, it makes it more obvious that you need to keep the original pointer around for the purposes of releasing the memory. The counter argument being that it gives the impression that you can free the original pointer once you have the return value, which you can't do because they both point at (different locations) in the same memory block.