I have written a program in which in the main function I declare an array of pointers and then I call a function which splits a given sentence and then want to assign it to the array of pointers in main(). I am unable to do. Can you please check the code pasted below:
int main(void)
{
char *data[3];
allocate(data);
/* Unable to print the strings here */
printf("Main is %s\n", data[0] );
printf(""
}
void allocate(char **dt)
{
int i;
char buf[] = "The great Scorpion";
char delims[] = " ";
size_t len;
char *p;
char *result = NULL;
result = strtok(buf," ");
*dt = result;
int j = 1;
while(result!=NULL)
{
result = strtok( NULL, delims );
dt[j]=result;
j++;
}
/* able to print values here */
printf( "result is %s\n", dt[0]);
printf( "result is %s\n", dt[1] );
printf( "result is %s\n", dt[2] );
}
Can anyone please help me out?
strtok does not allocate new strings, it returns a pointer to an existing string (and substitutes delimiters with null characters in place). So in allocate, you fill dt with pointers into buf. Since buf is an automatic variable, its lifetime ends when allocate returns, and all pointers in dt are invalidated.
If I remember correctly, strtok() doesn't do dynamic allocation, it actually modifies the string that you pass to in the first time you call it. So, in this case, it modifies buf. So dt is an array of pointers into buf. And when you exit the function, buf is destroyed.
Actually you might just add static to your buf declaration.
Ok,
You have an allocate function to which you pass the return pointer array.
Inside the function you allocate a string on the stack, and,
Make the strtok return pointers to this stack area outside the function
At that point you have 'dangling' pointers to the string -- effectively
Then you call printf which kill the data in unallocated stack
you miss the strings in printf.
If you want to do this, the correct way would be to
really allocate strings in your allocate function and
then free them from main after you are done with them.
The older way to work with strtok was to use strdup in the allocate and free later.
OldStuff...
I think you need to pass the &data to your allocate function.
Either that, or i am not all awake yet.
As a small aside (that won't actually have an effect on your program), you loop is structured wrong.
int j = 1;
while(result!=NULL)
{
result = strtok( NULL, delims );
dt[j]=result;
j++;
}
You set dt[0], dt[1], and dt[2], correctly. However due the the nature of your loop (you check, call strtok, then insert into dt,) you're also assigning NULL into dt[3]. This would probably run fine in this trivial example, but you're probably trashing your stack. You should really structure your loop like
result = strtok(buf," ");
int j=0
while(result != NULL)
{
dt[j]=result;
j++;
result = strtok(NULL, delims);
}
You're trying to return the address of a local, non-static variable; once the allocate() function exits, the buf array no longer exists, so the pointers in your data array are no longer pointing to anything meaningful.
What you need to do is save a copy of the token, rather than just a pointer to it:
void allocate(char **dt)
{
char buf[] = "The Great Scorpion";
char delim[] = " ";
size_t i = 0;
char *result = strtok(buf, delim);
while (result)
{
dt[i] = malloc(strlen(result) + 1);
if (dt[i])
{
strcpy(dt[i++], result);
}
result = strtok(NULL, delim);
}
}
int main(void)
{
char *data[3];
allocate(data);
...
}
Alternately, you can define data to be a 2D array of char, rather than just an array of pointers, but you need to make sure it's sized to handle the maximum string length; also, the type passed to allocate changes:
#define STRING_SIZE ... /* large enough for longest string */
void allocate(char (*dt)[STRING_SIZE+1])
{
char buf[] = "The Great Scorpion";
char delim[] = " ";
size_t i = 0;
char *result = strtok(buf, delim);
while (result)
{
strcpy(dt[i++], result);
result = strtok(NULL, delim);
}
}
int main(void)
{
char data[3][STRING_SIZE];
allocate(data);
...
}
Dynamically allocating memory is more flexible, but requires some bookkeeping and you have to remember to free it when you're done with it.
To not trash the stack, the while loop should be guarded with the size of the passed parameter "char *data[3]" which is 3 in this case, i.e extra parameter.
But i agree adding static to "static char buf[] = ...." is the quickest answer to get out of pointing to the de-allocated stack of a terminated function.
You haven't allocated the memory to be used inside data[X], just allocated data.
data[0] == null pointer
Related
I'm a C noob and I'm having problems with the following code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void split_string(char *conf, char *host_ip[]){
long unsigned int conf_len = sizeof(conf);
char line[50];
strcpy(line, conf);
int i = 0;
char* token;
char* rest = line;
while ((token = strtok_r(rest, "_", &rest))){
host_ip[i] = token;
printf("-----------\n");
printf("token: %s\n", token);
i=i+1;
}
}
int main(){
char *my_conf[1];
my_conf[0] = "conf01_192.168.10.1";
char *host_ip[2];
split_string(my_conf[0], host_ip);
printf("%s\n",host_ip[0]);
printf("%s\n",host_ip[1]);
}
I want to modify the host_ip array inside the split_string function and then print the 2 resulting strings in the main.
However, the 2 last printf() are only printing unknown/random characters (maybe an address?). Any help?
There are 2 problems:
First, you're returning pointers to local variables. You can avoid this by strduping the strings and freeing in the caller.
Second:
On the first call to strtok_r(), str should point to the string to be parsed, and the value of saveptr is ignored. In subsequent calls, str should be NULL, and saveptr should be unchanged since the previous call.
I.e. you must NULL for the first argument after the first iteration in the loop. Nowhere is it said that it is OK to use the same pointer for both arguments.
This is because the strtok_r is an almost drop-in replacement to the braindead strtok, with just one extra argument, so that you could even wrap it with a macro...
Thus we get
char *start = rest;
while ((token = strtok_r(start, "_", &rest))){
host_ip[i] = strdup(token);
printf("-----------\n");
printf("token: %s\n", token);
i++;
start = NULL;
}
and in the caller:
free(host_ip[0]);
free(host_ip[1]);
You are storing address of local variable (line) which is in stack.Stack is LIFO and has valid data for local variables in its stack memory during its function life time.after that, the same stack memory will be allocated to another function's local variables. So, data stores in line【50】's memory will be invalid after coming out of string_split function
I used this code to print some string,but it does not print any thing.What is the problem?
char* getNotFilledEncryptionParams(void)
{
char* nofilledStr;
char tmp[3];
const char * arr[]= {" P,"," Q,"," A,"," B,"," C,"," R,"," S0,","S1,","S2,","F1,","G1"};
for(i=0;i<11;i++)
{
if(filledParams[i] == 0)
{
strcpy(tmp,arr[i]);
strcat(nofilledStr,tmp);
}
}
return nofilledStr;
}
Usage:
int main(void){
char *remaining;
remaining = getNotFilledEncryptionParams();
printf("\r\n Remaining item:%s",remaining);
}
I think the problem is in const char * arr[] and I changed it,but the problem remains.
You didn't allocate any memory for noFilledStr, so its value is indeterminate and strcat(noFilledStr, tmp) is undefined.
Use malloc to allocate memory and initialize noFilledStr with the returned pointer:
char* noFilledStr = malloc(number_of_bytes);
The strings in arr are char[4], not char[3] (do not forget the null byte!). tmp is too small to hold them, so strcpy(tmp, arr[i]) writes out of bounds.
You are trying to build the string to return in the location pointed to by nofilledStr but this pointer is pointing somewhere as you do not initialize it. You could use a sufficiently large static char[] array if you do not have to deal with multiple threads. Otherwise, use malloc() and require the caller to free() the returned string when he is done with it.
I have no idea what is wrong with the following code. I perused stackoverflow without finding much assistance.
char * abbreviate_name( const char * full_name) {
int length = strlen(full_name) + 1;
char * final = malloc(length);
*answer = '\0';
char ptr[51];
// above is where I declare all my variables
strncpy(ptr, full_name, length); // copy full_name because it is a const
// ...
final = &ptr[1]; // this line copies all of ptr when I do a prinf on it
I'm just wondering how to get the first letter of ptr.
I tried playing with the ptrs and addresses and couldn't get it to work.
to get the first char of a pointer you can either go *ptr or ptr[0].
Your code has other problems though, assign to final doesn't copy, it just points final to another location, in this case you are going to point to a stack variable and it's going to fail badly.
instead, just strcpy into final and get rid of "ptr"
final[0] = ptr[0];
*final = *ptr;
final[0] = *ptr;
*final = ptr[0];
You can, in addition to Keith's answer, accomplish the allocation and copy of full_name to final in one step by making use of strdup:
char *abbreviate_name (const char *full_name) {
char *final = strdup (full_name);
...
strdup will call malloc to dynamically allocate storage sufficient to hold full_name. Just as if you had used malloc, you are responsible for freeing the memory when it is no longer needed.
I am probably shooting in the dark and writing an answer which is very much prone to down-votes, but let me begin.
Probably OP is looking for a function which provides and abbreviated version of a string, thus first letter of each of the given words in a string ( full_string ). reason I thought this because of char * return type and function name.
char * abbreviate_name( const char * full_name) ;
If I am correct in understanding the question, then you are probably looking for
strtok
and here is a snippet for extracting what you are looking for
char *str1, *saveptr1, *token ;
for ( str1 = full_name; ; str1 = NULL) {
token = strtok_r(str1, " " , &saveptr1); // delimited with " "
if ( token == NULL ) {
break; // break once no tokens available
}
printf("%c ", *token); // Extract first letter for each word, which probably form the abbreviated string you are looking for
}
I'm trying to write a function will convert the characters from an array into ints so that I can produce a sum or other math process for each group. I know that first I have to use strtok to get rid of the spaces and '+'. I've been trying to first at least start with getting strtok to work but it keeps saying segmentation fault when I try to run it.
Any help?
#include <string.h>
#include <stdio.h>
int main(void)
{
char* string[] = { "10 + 20", "1 + 3 + 6 + 8" };
sum(string[0]);
}
int sum(char* s)
{
char *stringcopy = malloc( strlen(s) + 1 );
char* del = " +";
char* token;
int i;
stringcopy = s; /* 'copy' problem here */
token = strtok(stringcopy, del);
while( token ) {
printf("%s\n", token);
token = strtok(NULL, del);
}
return 11; /* placeholder until I get the sum */
}
There is a simple reason strtok gives you a segmentation fault:
You are running it on a string literal, which despite having type char[n] is an immutable object.
strtok modifies any string you run it on!
The work-around is simple: Run on a copy. Here a function for duplicating strings (most C libraries provide this non-standard function as char* strdup(const char*):
char* my_strdup(const char* s) {
size_t size = strlen(s)+1;
char* ret = malloc(size);
if(ret)
memcpy(ret, s, size);
return ret;
}
Don't forget to free() the copy later.
You tried doing so, but after getting off to a good start and reserving space for the string with malloc, you just discarded it (memory leak) by assigning a pointer to the literal to that same pointer.
This statement
textcopy = s; /* making copy for strtok */
does not do what you think.
In fact there us a memory leak because at first you allocated memory and textcopy got the address of the first byte of the storage
char *textcopy = malloc( strlen(s) + 1 );
and then you reassigned textcopy.
textcopy = s; /* making copy for strtok */
You have to use standard function strcpy instead
strcpy( textcopy, s ); /* making copy for strtok */
Also it would be better if the function would declared as
int stringSum(const char* s);
This line does not do what you thought it would:
textcopy = s; /* making copy for strtok */
No string is copied here. All that happens is that instead of pointing to the first byte of the block of memory that you just allocated for it (with malloc( strlen(s) + 1 )),
textcopy now points directly at the first byte of the literal string "10 + 20" that you passed to stringSum as s.
You probably wanted something like strcpy(textcopy, s). I had suggested strncpy earlier; strncpy(textcopy, s, strlen(s)) + 1 might work, but (as the comments explain) seems to be rather pointless to use in this context.
The line
textcopy = s; /* making copy for strtok */
doesn't make copy of s and put it in textcopy. Instead, you need to use:
strcpy(textcopy, s);
Have a
typedef struct person {
char name[20]
char surname[20]
} person_t;
I need to create a string like XXXXXX:YYYYYY with the function like
char* personToString(person_t *p). I tried to make it:
char* personToString(person_t* p) {
int n1,n2;
n1=strlen(p->name);
n2=strlen(p->surname);
char *p = (char*) malloc((n1+n2+2)*sizeof(char));
strcat(p,puser->name);
strcat(p,":");
strcat(p,puser->surname);
return p;
}
This give me a reasonable output but I have some errors testing with valgrind! I also think that there is a way more classy to write the function!
When you malloc memory for p the memory will hold garbage values. Strcat will append a string after the null character, but in an uninitialized string will hold random values.
Replace the first strcat with strcpy.
You need to
strcpy(p,puser->name);
not
strcat(p,puser->name);
malloc does not initialize the buffer to zero, so strcat is searching for a null byte in p first and probably not finding one, reading past the end of the buffer and thus crashing.
Instead of one strcpy plus two strcat you can also write one call to sprintf:
sprintf(p, "%s:%s", puser->name, puser->surname);
First you should call string copy, then strcat:
strcat(p,puser->name);
should be:
strcpy(p,puser->name);
because memory allocated with malloc function keeps values garbage, by doing strcat for first you are concatenating after garbage -- it also brings Undefined behaviour in your code.
You can use void* calloc (size_t num, size_t size); instead of malloc(), calloc function initialized allocated memory with 0 (then strcat() no problem).
Also dynamically allocated memory you should deallocate memory block using void free (void* ptr);) explicitly.
This looks good to me,
char* personToString( struct person_t *p )
{
int len = strlen(p->name) + strlen(p->surname) + 2; // holds ':' + NULL
char *str = malloc( len ); // Never cast malloc's return value in C
// Check str for NULL
if( str == NULL )
{
// we are out of memory
// handle errors
return NULL;
}
snprintf( str, len, "%s:%s", p->name, p->surname);
return str;
}
NOTE:
Never cast malloc's return value in C.
Use snprintf when multiple strcat is needed, its elegant.
free the return value str here in caller.
Fixed struct and char variables.