C strings by reference voodoo - c

I am a novice programmer and I hagly appreciate any advice with my problem here.
I've made a procedure that gets a string in buffer and parses it in three cunks, separated by the first 2 ";".
What I tried to do is to pass 3 char pointers in where I will store my parsed string. But all I got in the calling function is memory garbage. What am I doing wrong?
void parseomensaje(char buf[256], char **idNodo, char **idMensaje, char **mensaje){
char *temp;
temp=(char *)malloc(sizeof(buf));
strcpy(temp, buf);
printf("\ntemp adentro de la funcion = %s\n", temp);
idNodo = strtok (temp,";");
idMensaje = strtok (NULL, ";");
mensaje = strtok (NULL, "\0");
printf("\nADENTRO\nidNodo: %s\nidMensaje: %s\nmensaje: %s", idNodo, idMensaje, mensaje);
}
this function is called this way:
char *idnod=NULL;
char *idmen=NULL;
char *men=NULL;
idnod=(char *)malloc(sizeof(buffer));
idmen=(char *)malloc(sizeof(buffer));
men=(char *)malloc(sizeof(buffer));
parseomensaje (buffer, &idmen, &idnod, &men);
after parseomensaje is executed buffer contains its original string, but idmen, idnod and men are blank.
I was reading from tutorials that pointers names are pointers itself, so it is the same thing as passing a parameter by reference, but in case of a string I need to pass the pointer address to a pointer to pointer...
I was reading it from here, but I'm still trying to figure it out.
PD: I apologize for my English, please feel free to point any mistakes in my writing. :)

This is incorrect:
char *temp;
temp=(char *)malloc(sizeof(buf));
as the array will degrade to a char* within the function, so only sizeof(char*) bytes are being allocated (typically 4 or 8 bytes). If the actually length of buf is greater than 4 or 8 bytes then the program has undefined behaviour as the strcpy() will be writing beyond the bounds of the array. Basically:
void parseomensaje(char buf[256], char **idNodo, char **idMensaje, char **mensaje){
is equivalent to:
void parseomensaje(char* buf, char **idNodo, char **idMensaje, char **mensaje){
If you are, as you say, a novice programmer I would recommend avoiding dynamic memory allocation until you get more comfortable with the language. Modify the program to use fixed sized arrays instead of dynamically allocated memory (and prevent writing beyond the bounds of the arrays). Once you have that working and fully understand it then attempt to use dynamically allocated memory.

First of all you have multiple memory leaks in your program. Consider freeing every single memory chunk you've allocated thanks to malloc once you don't need them anymore.
As regard your function:
void parseomensaje(char buf[256], char **idNodo, char **idMensaje, char **mensaje)
Why do you pass char** pointers on your function? Pass char* instead. Because strtok is declared this way:
char *strtok(char *str, const char *delim);
Moreover, you don't need to allocate any memory before calling parseomensaje since strtok returns a pointer on your own memory, not new allocated one.

Related

Allocate memory to a specific "string"

I just started to learn memory management in C, and I didn't understand something. I want to allocate memory to a buffer that holds 12 bytes. which is the exact size of Hello World! without null terminator.
Then I want to append a string to the current string with strcat, and of course I cannot do that because I will get core dumped error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char mystr[12] = "Hello World!";
# allocate memory to mystr?
char *ptr = (char*) malloc(13 * sizeof(char));
strcat(mystr, "Hello");
return 0;
}
So, I don't know how can I allocate memory to the mystr variable if malloc doesn't take any other arguments except the target size.
I don't know how can I allocate memory to the mystr variable if malloc doesn't take any other arguments except the target size.
It is not possible to allocate extra memory to an array. Instead, what you want to do is allocate a new block of memory, copying the original string into the beginning of that memory (strcpy), then append the rest (strcat):
char *p = (char*) malloc((12 + 5 + 1) * sizeof(char));
strcpy(p, myptr);
strcat(p, "Hello");
12 for the first string, plus 5 for the second, plus one for the null-terminator.
Of course, since you know the final size, you could also simply allocate a big enough array instead of using malloc (and you can also use memcpy, too).
The problem should be that a string in C always end with a NULL character (also noted '\0'), so your string is actually 13 characters long. (That character is always automatically added with string literals and serves at telling where the string stops, because a string doesn't have a fixed length.)
So the strcat tries to read the string Hello world! followed by garbage (since the null-terminator is not included in the string).
P.S.: the error is not the core dumped but the Segmentation fault that precedes it, and this tells you that you are trying to change something in a segment you are not supposed to change (or execute/read something you are not supposed to -- this is a security feature).
Edit: after modifying the string mystr, you also need to change the length you allocate (in the malloc: use 13 * sizeof(char), or more simply here in this case sizeof(mystr)).
P.S. 2: also comments in C are started by //, not # (those are preprocessor directives).
you cant change the size of the array. mystr has to be also dynamically allocated.
int main(int argc, char const *argv[])
{
const char *ptr = "Hello World!";
const char *ptr2 = "hello";
char *mystr = malloc(strlen(ptr)+1);
strcpy(mystr, ptr);
mystr = realloc(mystr, strlen(mystr) + strlen(ptr2) + 1);
strcat(mystr, ptr2);
return 0;
}

char* leads to segfault but char[] doesn't [duplicate]

This question already has answers here:
Difference between char[] and char * in C [duplicate]
(3 answers)
Closed 7 years ago.
I think I know the answer to my own question but I would like to have confirmation that I understand this perfectly.
I wrote a function that returns a string. I pass a char* as a parameter, and the function modifies the pointer.
It works fine and here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_file_name(char* file_name_out)
{
char file_name[12+1];
char dir_name[50+12+1];
strcpy(file_name, "name.xml");
strcpy(dir_name, "/home/user/foo/bar/");
strcat(dir_name, file_name);
strcpy(file_name_out, dir_name); // Clarity - equivalent to a return
}
int main()
{
char file_name[100];
get_file_name(file_name);
printf(file_name);
return 0;
}
But if I replace char file_name[100]; by char *filename; or char *filename = "";, I get a segmentation fault in strcpy().
I am not sure why ?
My function takes a char* as a parameter and so does strcpy().
As far as I understand, char *filename = ""; creates a read-only string. strcpy() is then trying to write into a read-only variable, which is not allowed so the error makes sense.
But what happens when I write char *filename; ? My guess is that enough space to fit a pointer to a char is allocated on the stack, so I could write only one single character where my file_name_out points. A call to strcpy() would try to write at least 2, hence the error.
It would explain why the following code compiles and yields the expected output:
void foo(char* a, char* b)
{
*a = *b;
}
int main()
{
char a = 'A', b = 'B';
printf("a = %c, b = %c\n", a, b);
foo(&a, &b);
printf("a = %c, b = %c\n", a, b);
return 0;
}
On the other hand, if I use char file_name[100];, I allocate enough room on the stack for 100 characters, so strcpy() can happily write into file_name_out.
Am I right ?
As far as I understand, char *filename = ""; creates a read-only
string. strcpy() is then trying to write into a read-only variable,
which is not allowed so the error makes sense.
Yes, that's right. It is inherently different from declaring a character array. Initializing a character pointer to a string literal makes it read-only; attempting to change the contents of the string leads to UB.
But what happens when I write char *filename; ? My guess is that
enough space to fit a pointer to a char is allocated on the stack, so
I could write only one single character into my file_name_out
variable.
You allocate enough space to store a pointer to a character, and that's it. You can't write to *filename, not even a single character, because you didn't allocate space to store the contents pointed to by *filename. If you want to change the contents pointed to by filename, first you must initialize it to point to somewhere valid.
I think the issue here is that
char string[100];
allocates memory to string - which you can access using string as pointer
but
char * string;
does not allocate any memory to string so you get a seg fault.
to get memory you could use
string = calloc(100,sizeo(char));
for example, but you would need to remember at the end to free the memory with
free(string);
or you could get a memory leak.
another memory allocation route is with malloc
So in summary
char string[100];
is equivalent to
char * string;
string = calloc(100,sizeo(char));
...
free(string);
although strictly speaking calloc initializes all elements to zero, whereas in the string[100] decalaration the array elements are undefined unless you use
string[100]={}
if you use malloc instead to grad the memory the contents are undefined.
Another point made by #PaulRooney is that char string[100] gives memory allocation on the stack whereas calloc uses the heap. For more information about the heap and stack see this question and answers...
char file_name[100]; creates a contiguous array of 100 chars. In this case file_name is a pointer of type (char*) which points to the first element in the array.
char* file_name; creates a pointer. However, it is not initialized to a particular memory address. Further, this expression does not allocate memory.
char *filename;
Allocate nothing. Its just a pointer pointing to an unspecified location (the value is whatever was in that memory previously). Using this pointer will never work as it probably points outside the memory range your program is allowed to use.
char *filename = "";
Points to a piece of the programs data segment. As you already said it's read only and so attempting to change it leads to the segfault.
In your final example you are dealing with single char values, not strings of char values and your function foo treats them as such. So there is no issue with the length of buffers the char* values point to.

Dynamic memory allocation for pointer arrays

I'm am trying to write a program that reads in a series of strings from a text file and stores these in an array of strings, dynamically allocating memory for each element. My plan was to store each string in an array using a pointer and then grow the array size as more were read in. I am having trouble to understand why my test code below is not working. Is this a workable idea?
char *aPtr;
aPtr =(char*)malloc(sizeof(char));
aPtr[0]="This is a test";
printf("%s",aPtr[0]);
In C a string is a char*. A dynamic array of type T is represented as a pointer to T, so for char* that would be char**, not simply a char* the way you declared it.
The compiler, no doubt, has issued some warnings about it. Pay attention to these warnings, very often they help you understand what to do.
Here is how you can start your testing:
char **aPtr;
int len = 1; // Start with 1 string
aPtr = malloc(sizeof(char*) * len); // Do not cast malloc in C
aPtr[0] = "This is a test";
printf("%s",aPtr[0]); // This should work now.
char *str; //single pointer
With this you can store one string.
To store array of strings you Need two dimensional character array
or else array of character pointers or else double pointer
char str[10][50]; //two dimensional character array
If you declare like this you need not allocate memory as this is static declaration
char *str[10]; //array of pointers
Here you need to allocate memory for each pointer
loop through array to allocate memory for each pointer
for(i=0;i<10;i++)
str[i]=malloc(SIZE);
char **str; //double pointer
Here you need to allocate memory for Number of pointers and then allocate memory for each pointer .
str=malloc( sizeof(char *)*10);
And then loop through array allocate memory for each pointer
for(i=0;i<10;i++)
str[i]=malloc(SIZE);
char * aPtr;
is as pointer to a character, to which you allocated memory to hold exactly 1 character.
Doing
aPrt[0] = "test";
you address the memory for this one characters and try to store the address of the literal "test" to it. This will fail as this address most likley is wider then a character.
A fix to your code would be to allocate memory for a pointer to a character.
char ** aPtr = malloc(sizeof(char *));
aPtr[0] = "test";
printf("%s", aPtr[0]);
Are more elegant and more over robust approach would be to allocate the same (as well as adding the mandatory error checking) by doing:
char ** aPtr = malloc(sizeof *aPtr);
if (NULL == aPtr)
{
perror("malloc() failed");
exit(EXIT_FAILURE);
}
...
You are doing it totally wrong. The correct version of your code should be like this:
int main ()
{
char *aPtr;
aPtr =(char*)malloc(20*sizeof(char));
aPtr ="This is a test";
printf("%s",aPtr);
}
You can use pointer array. if you want to store multiple string. Yes I know using for loop will be easy. But I am trying to explain in simple way even a beginner can understand.
int main ()
{
char *aPtr[10];
aPtr[0] =(char*)malloc(20*sizeof(char));
aPtr[0] ="This is a test";
aPtr[1] =(char*)malloc(20*sizeof(char));
aPtr[1] ="This is a test2";
printf("%s\n%s\n",aPtr[0],aPtr[1]);
}

why does this pointer manipulation fail?

I'm working my way in understanding pointers. I wrote this string copy functionality in C.
#include<stdio.h>
char *my_strcpy(char *dest, char *source)
{
while (*source != '\0')
{
*dest++ = *source++;
}
*dest = '\0';
return dest;
}
int main(void)
{
char* temp="temp";
char* temp1=NULL;
my_strcpy(temp1,temp);
puts(temp1);
return 0;
}
This program gives a segfault.If I change char* temp1=NULL to char* temp1 still it fails. If I change char* temp1 to char temp1[80], the code works. The code also works if char temp1[1] and gives the output as temp. I was thinking the output should be t. Why is it like this and why do I get error with char* temp.
Because you're not allocating space for the destination string. You're trying to write to memory at position NULL (almost certainly 0x00).
Try char* temp1= malloc(strlen(temp)+1); or something like it. That will allocate some memory and then you can copy the characters into it. The +1 is for the trailing null character.
If you wrote Java and friends, it would prevent you from accessing memory off the end of the array. But at a language level, C lets you write to memory anywhere you want. And then crash (hopefully immediately but maybe next week). Arrays aren't strictly enforced data types, they are just conventions for allocating and referencing memory.
If you create it as char temp1[1] then you are allocating some memory on the stack. Memory near that may be accessible (you can read and write to it) but you will be scribbling over other memory intended for something else. This is a classic memory bug.
Also style: I personally advise against using the return values from ++s. It's harder to read and makes you think twice.
*dest = *source;
dest++;
source++;
Is clearer. But that's just my opinion.
You must to allocate space for the destination parameter.
When you use char temp1[80], you allocate 80 bytes in the memory.
You can allocate memory in static way, like array, or use the malloc function

pass strings by reference in C

I'm having trouble figuring out how to pass strings back through the parameters of a function. I'm new to programming, so I imagine this this probably a beginner question. Any help you could give would be most appreciated. This code seg faults, and I'm not sure why, but I'm providing my code to show what I have so far.
I have made this a community wiki, so feel free to edit.
P.S. This is not homework.
This is the original version
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void
fn(char *baz, char *foo, char *bar)
{
char *pch;
/* this is the part I'm having trouble with */
pch = strtok (baz, ":");
foo = malloc(strlen(pch));
strcpy(foo, pch);
pch = strtok (NULL, ":");
bar = malloc(strlen(pch));
strcpy(bar, pch);
return;
}
int
main(void)
{
char *mybaz, *myfoo, *mybar;
mybaz = "hello:world";
fn(mybaz, myfoo, mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
}
UPDATE Here's an updated version with some of the suggestions implemented:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINE 1024
void
fn(char *baz, char **foo, char **bar)
{
char line[MAXLINE];
char *pch;
strcpy(line, baz);
pch = strtok (line, ":");
*foo = (char *)malloc(strlen(pch)+1);
(*foo)[strlen(pch)] = '\n';
strcpy(*foo, pch);
pch = strtok (NULL, ":");
*bar = (char *)malloc(strlen(pch)+1);
(*bar)[strlen(pch)] = '\n';
strcpy(*bar, pch);
return;
}
int
main(void)
{
char *mybaz, *myfoo, *mybar;
mybaz = "hello:world";
fn(mybaz, &myfoo, &mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
free(myfoo);
free(mybar);
}
First thing, those mallocs should be for strlen(whatever)+1 bytes. C strings have a 0 character to indicate the end, called the NUL terminator, and it isn't included in the length measured by strlen.
Next thing, strtok modifies the string you're searching. You are passing it a pointer to a string which you're not allowed to modify (you can't modify literal strings). That could be the cause of the segfault. So instead of using a pointer to the non-modifiable string literal, you could copy it to your own, modifiable buffer, like this:
char mybaz[] = "hello:world";
What this does is put a size 12 char array on the stack, and copy the bytes of the string literal into that array. It works because the compiler knows, at compile time, how long the string is, and can make space accordingly. This saves using malloc for that particular copy.
The problem you have with references is that you're currently passing the value of mybaz, myfoo, and mybar into your function. You can't modify the caller's variables unless you pass a pointer to myfoo and mybar. Since myfoo is a char*, a pointer to it is a char**:
void
fn(char *baz, char **foo, char **bar) // take pointers-to-pointers
*foo = malloc(...); // set the value pointed to by foo
fn(mybaz, &myfoo, &mybar); // pass pointers to myfoo and mybar
Modifying foo in the function in your code has absolutely no effect on myfoo. myfoo is uninitialised, so if neither of the first two things is causing it, the segfault is most likely occurring when you come to print using that uninitialised pointer.
Once you've got it basically working, you might want to add some error-handling. strtok can return NULL if it doesn't find the separator it's looking for, and you can't call strlen with NULL. malloc can return NULL if there isn't enough memory, and you can't call strcpy with NULL either.
One thing everyone is overlooking is that you're calling strtok on an array stored in const memory. strtok writes to the array you pass it so make sure you copy that to a temporary array before calling strtok on it or just allocate the original one like:
char mybaz[] = "hello:world";
Ooh yes, little problem there.
As a rule, if you're going to be manipulating strings from inside a function, the storage for those strings had better be outside the function. The easy way to achieve this is to declare arrays outside the function (e.g. in main()) and to pass the arrays (which automatically become pointers to their beginnings) to the function. This works fine as long as your result strings don't overflow the space allocated in the arrays.
You've gone the more versatile but slightly more difficult route: You use malloc() to create space for your results (good so far!) and then try to assign the malloc'd space to the pointers you pass in. That, alas, will not work.
The pointer coming in is a value; you cannot change it. The solution is to pass a pointer to a pointer, and use it inside the function to change what the pointer is pointing to.
If you got that, great. If not, please ask for more clarification.
In C you typically pass by reference by passing 1) a pointer of the first element of the array, and 2) the length of the array.
The length of the array can be ommitted sometimes if you are sure about your buffer size, and one would know the length of the string by looking for a null terminated character (A character with the value of 0 or '\0'.
It seems from your code example though that you are trying to set the value of what a pointer points to. So you probably want a char** pointer. And you would pass in the address of your char* variable(s) that you want to set.
You're wanting to pass back 2 pointers. So you need to call it with a pair of pointers to pointers. Something like this:
void
fn(char *baz, char **foo, char **bar) {
...
*foo = malloc( ... );
...
*bar = malloc( ... );
...
}
the code most likely segfaults because you are allocating space for the string but forgetting that a string has an extra byte on the end, the null terminator.
Also you are only passing a pointer in. Since a pointer is a 32-bit value (on a 32-bit machine) you are simply passing the value of the unitialised pointer into "fn". In the same way you wouldn't expact an integer passed into a function to be returned to the calling function (without explicitly returning it) you can't expect a pointer to do the same. So the new pointer values are never returned back to the main function. Usually you do this by passing a pointer to a pointer in C.
Also don't forget to free dynamically allocated memory!!
void
fn(char *baz, char **foo, char **bar)
{
char *pch;
/* this is the part I'm having trouble with */
pch = strtok (baz, ":");
*foo = malloc(strlen(pch) + 1);
strcpy(*foo, pch);
pch = strtok (NULL, ":");
*bar = malloc(strlen(pch) + 1);
strcpy(*bar, pch);
return;
}
int
main(void)
{
char *mybaz, *myfoo, *mybar;
mybaz = "hello:world";
fn(mybaz, &myfoo, &mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
free( myFoo );
free( myBar );
}
Other answers describe how to fix your answer to work, but an easy way to accomplish what you mean to do is strdup(), which allocates new memory of the appropriate size and copies the correct characters in.
Still need to fix the business with char* vs char**, though. There's just no way around that.
The essential problem is that although storage is ever allocated (with malloc()) for the results you are trying to return as myfoo and mybar, the pointers to those allocations are not actually returned to main(). As a result, the later call to printf() is quite likely to dump core.
The solution is to declare the arguments as ponter to pointer to char, and pass the addresses of myfoo and mybar to fn. Something like this (untested) should do the trick:
void
fn(char *baz, char **foo, char **bar)
{
char *pch;
/* this is the part I'm having trouble with */
pch = strtok (baz, ":");
*foo = malloc(strlen(pch)+1); /* include space for NUL termination */
strcpy(*foo, pch);
pch = strtok (NULL, ":");
*bar = malloc(strlen(pch)+1); /* include space for NUL termination */
strcpy(*bar, pch);
return;
}
int
main(void)
{
char mybaz[] = "hello:world";
char *myfoo, *mybar;
fn(mybaz, &myfoo, &mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
free(myfoo);
free(mybar);
}
Don't forget the free each allocated string at some later point or you will create memory leaks.
To do both the malloc() and strcpy() in one call, it would be better to use strdup(), as it also remembers to allocate room for the terminating NUL which you left out of your code as written. *foo = strdup(pch) is much clearer and easier to maintain that the alternative. Since strdup() is POSIX and not ANSI C, you might need to implement it yourself, but the effort is well repaid by the resulting clarity for this kind of usage.
The other traditional way to return a string from a C function is for the caller to allocate the storage and provide its address to the function. This is the technique used by sprintf(), for example. It suffers from the problem that there is no way to make such a call site completely safe against buffer overrun bugs caused by the called function assuming more space has been allocated than is actually available. The traditional repair for this problem is to require that a buffer length argument also be passed, and to carefully validate both the actual allocation and the length claimed at the call site in code review.
Edit:
The actual segfault you are getting is likely to be inside strtok(), not printf() because your sample as written is attempting to pass a string constant to strtok() which must be able to modify the string. This is officially Undefined Behavior.
The fix for this issue is to make sure that bybaz is declared as an initialized array, and not as a pointer to char. The initialized array will be located in writable memory, while the string constant is likely to be located in read-only memory. In many cases, string constants are stored in the same part of memory used to hold the executable code itself, and modern systems all try to make it difficult for a program to modify its own running code.
In the embedded systems I work on for a living, the code is likely to be stored in a ROM of some sort, and cannot be physically modified.

Resources