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);
Related
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 am new to C and working on a project where I need to be able to get a substring but I am having difficulty as there is a compiler warning about the initialisation and a core dump if I attempt to run the program which I am not sure how to resolve.
I have a function called substring which passes in the source string, the start index and to end index.
Below is my substring function.
char *substring(char * src, int from, int to)
{
char * dst = "\0";
strncpy(dst, src+from, to);
return dst;
}
Below is how I am calling the function
char * debug = substring(rowReport[bPartyColIndex], 1, 2);
rowReport is a MYSQL_ROW, and bPartyColIndex is just an int equal 0 to reference the correct column from the MYSQL_ROW.
At the moment the line above has a compiler warning of:
warning: initialization makes pointer from integer without a cast
which I am unable to determine how to fix this warning.
If I try and run the program I then get a coredump which says that it is a segmentation fault within the substring function performing the strncpy.
char * dst = "\0";
strncpy(dst, src+from, to);
That's why there's a segfault. Assigning dst with \0 isn't correct ! Actually, dst isn't big enough to store the src + from bytes. You should allocate it instead:
char *substring(char * src, int from, int to)
{
size_t src_size = to + 1 - from;
char * dst = malloc(src_size); // Assuming str + from is ok
if (dst != 0)
strncpy(dst, src+from, src_size);
return dst;
}
In this case, you will have to free dst :
char * debug = substring(rowReport[bPartyColIndex], 1, 2);
puts(debug);
free(debug);
You need to allocate new memory for your substring, or have the caller pass in the desired buffer. What you're trying won't work, you are never allocating the storage.
You need something like:
char * substring(const char *str, int from, int to)
{
const size_t len = to - from + 1;
char *out = malloc(len + 1);
if(out != NULL)
{
memcpy(out, str + from, len);
out[len] = '\0';
}
return out;
}
Then the caller needs to free() the returned pointer when done with it.
Your substring function, by itself, has some issues. You are not allocating any space for dst and copying into it. That could lead to a seg fault. You are also not checking if either from or to my go beyond the end of string (can be checked with strlen).
You should also check that from is less than to.
First:
char * dst = "\0";
strncpy(dst, src+from, to);
You are writing to a string literal but string literals are immutable in C. This invokes undefined behavior.
Second:
rowReport[bPartyColIndex] has to be a char * but it is of a different type.
You didn't specify the type of rowReport in your question, but assuming it is a char array you have to pass &rowReport[bPartyColIndex] instead of rowReport[bPartyColIndex] to substring function.
I am a beginner in C. I wanted to make strcat function using pointers. I made it but don't know what is wrong with it. I used gcc compiler and it gave segmentation fault output.
#include<stdio.h>
#include<string.h>
char scat(char *,char *);
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
while(*q!='\0') printf("the concatenated string is %c",*q);
}
char *scat(char *s,char *t)
{
char *p=s;
while(*p!='\0'){
p++;
}
while(*t!='\0'){
*p=*t;
p++;
t++;
}
return p-s-t;
}
This one works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *scat(char *,char *); /* 1: your prototype was wrong */
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
printf("cat: %s\n", q); /* 2: you can use %s to print a string */
free(q);
}
char *scat(char *s,char *t)
{
char *p=malloc(strlen(s)+strlen(t)+1); /* 3: you will have to reserve memory to hold the copy. */
int ptr =0, temp = 0; /* 4 initialise some helpers */
while(s[temp]!='\0'){ /* 5. use the temp to "walk" over string 1 */
p[ptr++] = s[temp++];
}
temp=0;
while(t[temp]!='\0'){ /* and string two */
p[ptr++]=t[temp++];
}
return p;
}
You have to allocate new space to copy at the end of s. Otherwise, your while loo[ will go in memory you don't have access to.
You shoul learn about malloc() here.
It is undefined behaviour to modify a string literal and s, and eventually p, is pointing to a string literal:
char* s = "james";
s is passed as first argument to scat() to which the local char* p is assigned and then:
*p=*t;
which on first invocation is attempting to overwite the null character an the end of the string literal "james".
A possible solution would be to use malloc() to allocate a buffer large enough to contain the concatentation of the two input strings:
char* result = malloc(strlen(s) + strlen(p) + 1); /* + 1 for null terminator. */
and copy them into it. The caller must remember to free() the returned char*.
You may find the list of frequently asked pointer questions useful.
Because p goes till the end of the string and then it starts advancing to illegal memory.
That is why you get segmentation fault.
It's because s points to "james\0", string literal & you cannot modify constant.
Change char *s="james"; to char s[50]="james";.
You need to understand the basics of pointers.
a char * is not a string or array of characters, it's the address of the beginning of the data.
you can't do a char * - char* !!
This is a good tutorial to start with
you will have to use malloc
You get a segmentation fault because you move the pointer to the end of s and then just start writing the data of p to the memory directly following s. What makes you believe there is writable memory available after s? Any attempt to write data to non-writable memory results in a segmentation fault and it looks like the memory following s is not writable (which is to expect, since "string constants" are usually stored in read-only memory).
Several things look out of order.
First keep in mind that when you want to return a pointer to something created within a function it needs to have been malloc'ed somewhere. Much easier if you pass the destination as an argument to the function. If you follow the former approach, don't forget to free() it when you're done with it.
Also, the function scat has to return a pointer in the declaration i.e. char *scat, not char scat.
Finally you don't need that loop to print the string, printf("%s", string); will take care of printing the string for you (provided it's terminated).
At first, your code will be in infinte loop because of the below line. you were supposed to use curely braces by including "p++; t++ " statements.
while(*t!='\0')
*p=*t;
though you do like this, you are trying to alter the content of the string literal. which will result in undefined behavior like segmentation fault.
A sequence of characters enclosed with in double quotes are called as string literal. it is also called as "string". String is fixed in size. once you created, you can't extend its size and alter the contents. Doing so will lead to undefined behavior.
To solve this problem , you need to allocate a new character array whose size is sum of the length of two strings passed. then append the two strings into the new array. finally return the address of the new array.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* scat(char *,char *);
void append(char *t , char *s);
int main(void)
{
char *s="james";
char *t="bond";
char *n = scat(s,t);
printf("the concatenated string is %s",n);
return 0;
}
char* scat(char *s,char *t)
{
int len = strlen(s) + strlen(t);
char *tmp = (char *)malloc(sizeof(char)* len);
append(tmp,s);
append(tmp,t);
return tmp;
}
void append(char *t , char *s)
{
//move pointer t to end of the string it points.
while(*t != '\0'){
t++;
}
while( *s != '\0' ){
*t = *s;
t++;
s++;
}
}
in the following code when i use fwrite its giving correct o/p. While memcpy is not working.
typedef struct
{
char *p1;
char *p2;
} node;
char s[] = "hello";
char t[] =" there";
node t1, t2;
char str;
FILE op_f;
t1.p1 = malloc(sizeof(strlen(s));
t1.p2 = malloc(sizeof(strlen(s));
t2.p1 = malloc(sizeof(strlen(s));
t2.p2 = malloc(sizeof(strlen(s));
t1.p1 = s;
t1.p2 = t;
copy(&t1,&t2);
str = malloc(sizeof(strlen(s) + strlen(t));
/* gives o/p hello there */
fwrite(t2.p1,1,strlen(s),op_f);
fwrite(t2.p1,2,strlen(s),op_f);
/* gives o/p there */
memcpy(str,t2.p1,strlen(s));
memcpy(str,t2.p2,strlen(s));
Is there any way to copy buffer to str ??
PS: above code is just for reference not the actual code
You should declare str as char array, not a single char:
char str[500];
when str is declared as array, the str is a pointer (to the first element of array). And in your code - str was a char, but not a pointer. Memcpy needs pointers as first and second arguments
Also, use malloc for strings without sizeof:
t1.p2 = malloc(strlen(s)+1);
Also, fwrite is used incorrectly, because the op_f is not initialized with fopen like:
op_f = fopen("filename.txt", "w");
Strings stored in char arrays need one extra byte for a terminator. When computing the size you need to add 1 extra position:
t1.p1 = malloc(strlen(s) + 1);
This code
t1.p1 = s;
doesn't copy the text from s to p1, but sets p1 to point to the same string as s.
This part
str = malloc(strlen(s) + strlen(t));
doesn't work because str is a single char and not a char*. You could try
char* str = malloc(strlen(s) + strlen(t) + 1);
If you really intend this to be tagged C++, you should consider using std::string instead. It handles all of these details.
I just noticed you use 'char str' instead of 'char *str', so the result of malloc (which is a pointer to string) it not correctly stored in the variable.
Also, when you malloc, you need to calculate the size the following way: strlen(s) + strlen(t) + 1. The extra byte is for the terminating NULL character. And you don't need to use sizeof there. The finally statement will look like:
str = malloc(strlen(s) + strlen(t) + 1);
/* These are static. You SHOULD NOT write to either s or t! */
char s[] = "hello";
char t[] =" there";
typedef struct
{
char *p1;
char *p2;
} node;
node t1, t2;
/* I think you wanted "*str" here... */
char *str;
/* You definitely want "length of string + 1" here */
t1.p1 = malloc(strlen(s) + 1);
strcpy (t1.p1, s);
...
/* strcpy() and strcat() might be applicable here */
/* strncpy() and strncpy() might be even better - it depends... */
str = malloc(strlen(s)+1 + strlen(t)+1);
strcpy (str, s);
strcat (str, t);
firstly, you should be using strcpy when working with strings (if they are null terminated), as your code currently has a bug which is hidden by the fact 'hello' and 'there' are the same length, to fix it you should be doing (same applies to the malloc calls):
fwrite(t2.p1,sizeof(char),strlen(t2.p1),op_f);
fwrite(t2.p2,sizeof(char),strlen(t2.p2),op_f); //was also a bug here, you used p1 instead of p2 and the size of each element should have been 1
/* gives o/p there */
memcpy(str,t2.p1,strlen(t2.p1));
memcpy(str,t2.p2,strlen(t2.p2));
Your real problem originates because memcpy doesn't increment pointers, hence you should be doing:
strcpy(str,t2.p1);
strcat(str,t2.p2);
or if you really want to use memcpy:
memcpy(str,t2.p1,strlen(t2.p1));
memcpy(str + strlen(t2.p1) - 1,t2.p2,strlen(t2.p2));
finally, your malloc's return pointers, not a char, so str should be a char*.
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