I have an char array and I am trying to copy a part of it (tokenization) into 0th index of array of pointer to char using the strncpy function. But during runtime a segmentation fault occurs.
Code example:
char array[30] = "ls -l";
char* args[10];
strncpy(args[0], array + 0, 2);
char *args[10] has the following declaration:
declare args as array 10 of pointer to char
That is to say, we have an array of uninitialized pointers. We'll need to make those pointers point somewhere first, before trying to place characters there. Remembering that we must NUL terminate ('\0') C strings, we can simultaneously allocate and NUL out space for our string by using calloc.
This will make space for just 'l', 's', and our mandatory '\0'.
char original_command[30] = "ls -l";
char *args[10] = { 0 };
args[0] = calloc(3, sizeof (char));
strncpy(args[0], original_command, 2);
Alternatively, we can use malloc, but we must remember the NUL terminating byte.
args[0] = malloc(3);
strncpy(args[0], original_command, 2);
args[0][2] = '\0';
It's generally a good idea to always initialize our variables - see how we initialize our args array to be full of NULL pointers (0). Makes it very clear they don't point anywhere useful yet.
Also note that strncpy does not place a NUL terminating byte if it was not found in the first n bytes of our source string. This is why it's very important to manually terminate our destination string.
Additionally, any call to an *alloc function must be matched later by a call to free, when we are finished using that memory.
/* Do whatever needs to be done */
/* ... */
free(args[0]);
You need to allocate space for the copied string content; char* args[10] reserves only space for holding the pointer to the content, not for the content itself. And don't forget to reserve space for the string terminating character '\0' then.
args[0] = malloc(2+1);
strncpy(agrs[0],array+0,2+1);
agrs[0][2] = '\0';
Related
i am trying to convert a string (example: "hey there mister") into a double pointer that's pointing to every word in the sentence.
so: split_string->|pointer1|pointer2|pointer3| where pointer1->"hey", pointer2->"there" and pointer3->"mister".
char **split(char *s) {
char **nystreng = malloc(strlen(s));
char str[strlen(s)];
int i;
for(i = 0; i < strlen(s); i++){
str[i] = s[i];
}
char *temp;
temp = strtok(str, " ");
int teller = 0;
while(temp != NULL){
printf("%s\n", temp);
nystreng[teller] = temp;
temp = strtok(NULL, " ");
}
nystreng[teller++] = NULL;
//free(nystreng);
return nystreng;
}
My question is, why isnt this working?
Your code has multiple problems. Among them:
char **nystreng = malloc(strlen(s)); is just wrong. The amount of space you need is the size of a char * times the number pieces into which the string will be split plus one (for the NULL pointer terminator).
You fill *nystreng with pointers obtained from strtok() operating on local array str. Those pointers are valid only for the lifetime of str, which ends when the function returns.
You do not allocate space for a string terminator in str, and you do not write one, yet you pass it to strtok() as if it were a terminated string.
You do not increment teller inside your tokenization loop, so each token pointer overwrites the previous one.
You have an essential problem here in that you do not know before splitting the string how many pieces there will be. You could nevertheless get an upper bound on that by counting the number of delimiter characters and adding 1. You could then allocate space for that many char pointers plus one. Alternatively, you could build a linked list to handle the pieces as you tokenize, then allocate the result array only after you know how many pieces there are.
As for str, if you want to return pointers into it, as apparently you do, then it needs to be dynamically allocated, too. If your platform provides strdup() then you could just use
char *str = strdup(s);
Otherwise, you'll need to check the length, allocate enough space with malloc() (including space for the terminator), and copy the input string into the allocated space, presumably with strcpy(). Normally you would want to free the string afterward, but you must not do that if you are returning pointers into that space.
On the other hand, you might consider returning an array of strings that can be individually freed. For that, you must allocate each substring individually (strdup() would again be your friend if you have it), and in that event you would want to free the working space (or allow it to be cleaned up automatically if you use a VLA).
There are two things you need to do -
char str[strlen(s)]; //size should be equal to strlen(s)+1
Extra 1 for '\0'. Right now you pass str (not terminated with '\0') to strtok which causes undefined behaviour .
And second thing ,you also need allocate memory to each pointer of nystring and then use strcpy instead of pointing to temp(don't forget space for nul terminator).
char test[]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,3);
printf("%s",test);
I'm trying to grasp how exactly memcpy works and this is the example I've written so far.
This gives output as abcdexyz&vjunkcharacters
and the following message.
*** stack smashing detected ***: ./testcode terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7656dd5]
/lib/i386-linux-gnu/libc.so.6(+0xffd8a)[0xb7656d8a]
./testcode[0x8048797]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75704d3]
./testcode[0x80483a1]
What are the reasons behind this situation?
Root Cause:
char test[]={"abcde"};
Allocates enough memory space to store 5 characters only.
memcpy(test+5,test1,3);
Copies the data pointed by test1 beyond the allocated memory space.
Technically, writing beyond the bounds of an allocated memory in this fashion is Undefined Behavior, which means anything can happen.
What actually happens?
What actually happens here is memcpy copies characters beyond the allocated memory thus overwritting the NULL terminator which marks ends of your character array test.
Further, printf reads the contents from starting address of test till it encounters a random NULL thus printing out junk characters.
Solution:
You should ensure that destination buffer has enough memory allocated before you perform the memcpy. Since you intend to copy 3 characters, Your destination buffer test should be atleast:
5 + 3 + 1 byte for NULL terminator = 9 bytes
You can simply use:
char test[9]="abcde";
Your memcpy call does smash the stack, which is why you see that message. You're copying data past the end of your test array, which isn't allowed.
Doing it without an additional buffer
The most straight-forward approach, indeed, would be to avoid the copy:
#include <string.h>
#include <stdio.h>
int main() {
char a[] = "abcde";
char b[] = "xyz";
printf("%s%s\n", a, b);
return 0;
}
Doing it with memcpy
memcpy copies n bytes from src to dest. You need to keep track of copying null termination bytes of the strings correctly yourself.
#include <string.h>
#include <stdio.h>
int main() {
char a[] = "abcde";
char b[] = "xyz";
/* note that both strings add a '\0' termination */
char c[sizeof(a) + sizeof(b) - 1];
/* copy the content of a to c */
memcpy(c, a, sizeof(a));
/* copy the content of b to where a ends (concatenate the strings) */
memcpy(c + sizeof(a) - 1, b, sizeof(b));
/* note that the '\0' termination of the string is necessary to let
* functions like printf know where the string is over
*/
printf(c);
return 0;
}
Doing it with strcpy and strcat
Note that there's a lot of pitfalls dealing correctly with the null termination of the strings when using memcpy. To simplify this procedure for strings you should do the following.
If these are indeed strings and not random bytes you should stick to the string functions of the standard library. This is how it's done.
#include <string.h>
#include <stdio.h>
int main() {
char a[] = "abcde";
char b[] = "xyz";
/* note that both strings add a '\0' termination */
char c[sizeof(a) + sizeof(b) - 1];
/* copy the content of a to c */
strcpy(c, a);
/* copy the content of b to where a ends (concatenate the strings) */
strcat(c, b);
/* note that the '\0' termination of the string is necessary to let
* functions like printf know where the string is over
*/
printf(c);
return 0;
}
On knowing the size of the strings
Concerning knowing the size of the buffer, note that you can usually not simply do sizeof(a_string). If you pass a character array to a function it decays to a pointer and this operation no longer returns the expected size of the array but the size of the pointer.
For strings you need to issue strlen(a_string) which scans for the occurance of the null termination and returns the length of the string (not including the termination).
As for character buffers containing random data (or empty buffers that need to be written to) this approach doesn't work either. You always need to pass the size of the buffer as an additional parameter.
Variable test1 is in memory 4 chars, 3 plus the ending string terminator. Try this:
char test[9]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,4);
The line memcpy(test+5,test1,3); does the following in plain words:
"start at the last element of array "test" and copy 3 characters from array "test1" to there", which basically writes 2 characters beyond the length of the array 'test'.
So if you just want to play around with 'memcpy' define a 3rd array:
char test[]="abcde";
char test1[]="xyz";
char output[sizeof(test) + sizeof(test1)];
memset(output, 0, sizeof(output));
memcpy(&output[0],test,5);
memcpy(&output[5],test1,3);
printf("%s",output);
char *t = malloc(2);
t = "as";
t = realloc(t,sizeof(char)*6);
I am getting error "invalid pointer: 0x080488d4 *"..
I am getting strange errors in using memory allocation functions. Is there any good tuts/guides which could explain me memory allocation functions.
I am using linux..
Please help..
This is your problem:
char *t = malloc(2);
t = "as";
You probably thought this would copy the two-character string "as" into the buffer you just allocated. What it actually does is throw away (leak) the buffer, and change the pointer to instead point to the string constant "as", which is stored in read-only memory next to the machine code, not on the malloc heap. Because it's not on the heap, realloc looks at the pointer and says "no can do, that's not one of mine". (The computer is being nice to you by giving you this error; when you give realloc a pointer that wasn't returned by malloc or realloc, the computer is allowed to make demons fly out of your nose if it wants.)
This is how to do what you meant to do:
char *t = malloc(3);
strcpy(t, "as");
Note that you need space for three characters, not two, because of the implicit NUL terminator.
By the way, you never need to multiply anything by sizeof(char); it is 1 by definition.
That is not how you assign strings in C.
The correct syntax is:
char* t = malloc(3); // Reserve enough space for the null-terminator \0
strncpy(t, "as", 3);
// Copy up to 3 bytes from static string "as" to char* t.
// By specifying a maximum of 3 bytes, prevent buffer-overruns
Allocating 2-bytes is NOT enough for "as".
C-strings have a 1-byte null-terminator, so you need at least 3 bytes to hold "as\0".
(\0 represents the null-terminator)
The code you wrote: t = "as"; makes the pointer t "abandon" the formerly allocated memory, and instead point to the static string "as". The memory allocated with malloc is "leaked" and cannot be recovered (until the program terminates and the OS reclaims it).
After this, you can call realloc as you originally did.
However, you should not do t = realloc(t,6);. If realloc fails for any reason, you've lost your memory.
The preferred method is:
new_t = realloc(t, 6);
if (new_t != NULL) // realloc succeeded
{ t = new_t;
}
else
{ // Error in reallocating, but at least t still points to good memory!
}
Your code reassigns t, making it point elsewhere
char *t = malloc(2); //t=0xf00ba12
t = "as"; //t=0xbeefbeef
t = realloc(t,sizeof(char)*6); //confused because t is 0xbeefbeef, not 0xf00b412.
Instead use strcpy
char *t = malloc(3); //don't forget about the '\0'
strcpy(t, "as");
t = realloc(t, 6); //now the string has room to breathe
First off, don't do that:
char *t = malloc(2);
Do this instead:
char *t = malloc(2 * sizeof(char));
/* or this: */
char *t = calloc(2, sizeof(char));
It may not seem worth the effort, but otherwise you may run into problems later when you deal with types larger than 1 byte.
In this line:
t = "as";
You're assigning the address of the string literal "as", so your pointer no longer points to the memory you allocated. You need to copy the contents of the literal to your allocated memory:
char *t = calloc(3, sizeof(char));
/* "ar" is 3 char's: 'a', 'r' and the terminating 0 byte. */
strncpy(t, "ar", 3);
/* then later: */
t = realloc(t,sizeof(char)*6);
You can also just use strdup, which is safer:
#include <string.h>
char *t = strdup("ar");
t = realloc(t,sizeof(char)*6);
And don't forget to free the memory
free(t);
char *t = malloc(2);
this means you have created a pointer to a memory location that can hold 2 bytes
+-+-+
t -> | | |
+-+-+
when you do
t = "as";
now you made t point to somewhere else than what it originally was pointing to. now it no longer points to the heap
t = realloc(t,sizeof(char)*6);
now you are taking the pointer pointing to read only memory and try to realloc it.
when you use malloc you allocate space on the heap. t in this case is a pointer to that location, an address of where the block is.
in order to put something in that spot you need to copy the data there by dereferencing t, this is done by writing * in front of t:
*t = 'a'; // now 'a' is where t points
*(t+1)='s'; // now 's' is behind a, t still pointing to 'a'
however in C, a string is always terminated with a 0 (ASCII value) written as '\0' so in order to make it a string you need to append a \0
+-+-+--+
t -> |a|s|\0|
+-+-+--+
in order to do this you need to malloc 3 bytes instead, than you can add the \0 by writing *(t+2)='\0';
now t can be treated as pointing to a string and used in functions that takes strings as arguments e.g. strlen( t ) returns 2
When I do this
char *paths[10];
paths[0] = "123456";
printf(1,"%s\n",paths[0]);
printf(1,"%c\n",paths[0][2]);
Output:
123456
3
But when I you do this
char *paths[10];
paths[0][0]='1';
paths[0][1]='2';
paths[0][2]='3';
paths[0][3]='4';
paths[0][4]='5';
paths[0][5]='6';
printf(1,"%s\n",paths[0]);
printf(1,"%c\n",paths[0][2]);
Output:
(null)
3
Why it is null in this case?
How to create a string array using characters in C? I am a bit new to C and feeling some difficulties to program in C
You have a lot of options provided by various answers, I'm just adding a few points.
You can create a string array as follows:
I. You can create an array of read only strings as follows:
char *string_array0[] = {"Hello", "World", "!" };
This will create array of 3 read-only strings. You cannot modify the characters of the string in this case i.e. string_array0[0][0]='R'; is illegal.
II. You can declare array of pointers & use them as you need.
char *string_array1[2]; /* Array of pointers */
string_array1[0] = "Hey there"; /* This creates a read-only string */
/* string_array1[0][0] = 'R';*/ /* This is illegal, don't do this */
string_array1[1] = malloc(3); /* Allocate memory for 2 character string + 1 NULL char*/
if(NULL == string_array1[1])
{
/* Handle memory allocation failure*/
}
string_array1[1][0] = 'H';
string_array1[1][1] = 'i';
string_array1[1][2] = '\0'; /* This is important. You can use 0 or NULL as well*/
...
/* Use string_array1*/
...
free(string_array1[1]); /* Don't forget to free memory after usage */
III. You can declare a two dimensional character array.
char string_array2[2][4]; /* 2 strings of atmost 3 characters can be stored */
string_array2[0][0] = 'O';
string_array2[0][1] = 'l';
string_array2[0][2] = 'a';
string_array2[0][3] = '\0';
string_array2[1][0] = 'H';
string_array2[1][1] = 'i';
string_array2[1][2] = '\0'; /* NUL terminated, thus string of length of 2 */
IV. You can use pointer to pointer.
char ** string_array3;
int i;
string_array3 = malloc(2*sizeof(char*)); /* 2 strings */
if(NULL == string_array3)
{
/* Memory allocation failure handling*/
}
for( i = 0; i < 2; i++ )
{
string_array3[i] = malloc(3); /* String can hold at most 2 characters */
if(NULL == string_array3[i])
{
/* Memory allocation failure handling*/
}
}
strcpy(string_array3[0], "Hi");
string_array3[1][0]='I';
string_array3[1][1]='T';
string_array3[1][2]='\0';
/*Use string_array3*/
for( i = 0; i < 2; i++ )
{
free(string_array3[i]);
}
free(string_array3);
Points to remember:
If you are creating read-only string, you cannot change the character
in the string.
If you are filling the character array, make sure you have
memory to accommodate NUL character & make sure you terminate your
string data with NUL character.
If you are using pointers &
allocating memory, make sure you check if memory allocation is done
correctly & free the memory after use.
Use string functions from
string.h for string manipulation.
Hope this helps!
P.S.: printf(1,"%s\n",paths[0]); looks shady
char *paths[10];
paths[0][0]='1';
paths is an array of pointers. paths is not initialized to anything. So, it has garbage values. You need to use allocate memory using malloc. You just got unlucky that this program actually worked silently. Think of what address location would paths[0][0] would yield to assign 1 to it.
On the other hand, this worked because -
char *paths[10];
paths[0] = "123456";
"123456" is a string literal residing in the reading only location. So, it returns the starting address of that location which paths[0] is holding. To declare correctly -
const char* paths[10];
paths is an array of 10 pointers to char. However, the initial elements are pointers which can not be dereferenced. These are either wild (for an array in a function) or NULL for a static array. A wild pointer is an uninitialized one.
I would guess yours is static, since paths[0] is NULL. However, it could be a coincidence.
When you dereference a NULL or uninitialized pointer, you're reading or writing to memory you don't own. This causes undefined behavior, which can include crashing your program.
You're actually lucky it doesn't crash. This is probably because the compiler sees you're writing a constant to paths[0][2], and changes your printf to print the constant directly. You can not rely on this.
If you want to have a pointer you're allowed to write to, do:
paths[0] = malloc(string_length + 1);
string_length is the number of characters you can write. The 1 gives you room for a NUL. When you're done, you have to free it.
For your second example, if you know the size of each string you can write e.g.
char paths[10][6];
paths[0][0]='1';
...
paths[0][5]='6';
This way you have 10 strings of length 6 (and use only the first string so far).
You can define the string yourself, right after
#inlcude <stdio.h>
like this
typedef char string[];
and in main you can do this
string paths = "123456";
printf("%s\n", paths);
return 0;
so your code would look like this
#include <stdio.h>
typedef char string[];
int main() {
string paths = "123456";
printf("%s", paths);
}
include
#include <string.h>
int main()
{
char *array[10]={};
char* token;
token = "testing";
array[0] = "again";
strcat(array[0], token);
}
why it returns Segmentation fault?
I'm a little confused.
Technically, this isn't valid C. (It is valid C++, though.)
char *array[10]={};
You should use
char *array[10] = {0};
This declares an array of 10 pointers to char and initializes them all to null pointers.
char* token;
token = "testing";
This declares token as a pointer to char and points it at a string literal which is non-modifiable.
array[0] = "again";
This points the first char pointer of array at a string literal which (again) is a non-modifiable sequence of char.
strcat(array[0], token);
strcat concatenates one string onto the end of another string. For it to work the first string must be contained in writeable storage and have enough excess storage to contain the second string at and beyond the first terminating null character ('\0') in the first string. Neither of these hold for array[0] which is pointing directly at the string literal.
What you need to do is something like this. (You need to #include <string.h> and <stdlib.h>.)
I've gone for runtime calculation of sizes and dynamic allocation of memory as I'm assuming that you are doing a test for where the strings may not be of known size in the future. With the strings known at compile time you can avoid some (or most) of the work at compile time; but then you may as well do "againtesting" as a single string literal.
char* token = "testing";
char* other_token = "again";
/* Include extra space for string terminator */
size_t required_length = strlen(token) + strlen(other_token) + 1;
/* Dynamically allocated a big enough buffer */
array[0] = malloc( required_length );
strcpy( array[0], other_token );
strcat( array[0], token );
/* More code... */
/* Free allocated buffer */
free( array[0] );
How this works: char *array[10] is an array of 10 char * pointers (basically 10 same things as token).
token = "testing" creates static space somewhere in your program's memory at build time, and puts "testing" there. Then in run time, it puts address to that static "testing" to token.
array[0] = "again" does basically the same thing.
Then, strcat(array[0], token) takes address in array[0], and tries to add token's content to string at that address. Which gives you segfault, since array[0] points to read-only data segment in your memory.
How to do this properly:
char * initial = "first"; // pointer to static "first" string
char * second = "another"; // another one
char string[20]; // local array of 20 bytes
strcpy(string, initial); // copies first string into your read-write memory
strcat(string, second); // adds the second string there
Actually, if you don't want to shoot yourself in the foot, the better way to do something like the last two lines is:
snprintf(string, sizeof(string), "%s%s", initial, second);
snprintf then makes sure that you don't use more than 20 bytes of string. strcat and strcpy would happily go over the limit into invalid memory, and cause another run-time segfault or something worse (think security exploits) if the copied string were longer then the destination space.
To create a array of characters, char *array[10]={}; should instead be char array[10]={};
the segmentation fault occurs because array[0] points to "again", a string literal, and modifying string literals is a no-no(undefined behaviour)
If you're planning on changing the strings involved you should really allocate enough memory for what you need. For example instead of char *token; token = "testing"; you could use, say char token[20] = "testing";, which allows enough room for a 19 character string (plus the null byte at the end).
Similarly, you could use char array[10][20] = {"testing"}; to create an array of 10 strings and set the first one to testing.
You are putting a string at array[0] which is only one character.
Use array[0]='a' like this.