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
}
Related
I will say honestly, this isn't my code. It's my brother's who's studying with me but he's a ahead of me.
Please notice char *str and char *resultString in the function char *replaceWord().
/*Suppose you have a template letter.txt. You have to fill in values to a template. Letter.txt looks something like this:
Thanks {{name}} for purchasing {{item}} from our outlet {{outlet}}. Please visit our outlet {{outlet}} for any kind of problems. We plan to serve you again soon.
You have to write a program that will automatically fill the template.For this, read this file and replace these values:
{{name}} - Harry
{{item}} - Table Fan
{{outlet}} - Ram Laxmi fan outlet
Use file functions in c to accomplish the same.*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * replaceWord(const char * str, const char * oldWord, const char * newWord)
{
char * resultString;
int i, count = 0;
int newWordLength = strlen(newWord);
int oldWordLength = strlen(oldWord);
for (i = 0; str[i] != '\0'; i++)
{
if (strstr(&str[i], oldWord) == &str[i])
{
count++;
//Jumping over the word and continuing
i = i + oldWordLength - 1;
}
}
//dynamically allocation memory to resultString since it can be big or samll depending on the size of the newWord.
/*i = old string length , count = no. of times the word appeared in the string,
newWordLength-oldWordLength=difference between the new word and the old word
+1 for the null character '\0'
Basically we are saying that add the size required for the newWord to the strings length i.e i;
*/
resultString = (char *)malloc(i + count * (newWordLength - oldWordLength) + 1);
i = 0; //refreshing the i for the while loop
while (*str)
{
if (strstr(str, oldWord) == str)
{
strcpy(&resultString[i], newWord);
i += newWordLength;
str += oldWordLength;
}
else
{
resultString[i] = *str;
i+=1;
str+=1;
}
}
resultString[i] = '\0';
return resultString;
}
int main()
{
FILE *ptr = NULL;
FILE *ptr2 = NULL;
ptr = fopen("letter.txt", "r"); //where the template is stored
ptr2 = fopen("newLetter.txt", "w"); //where the new bill will be stored.
char str[200];
fgets(str, 200, ptr); //store the bill template in the str variable.
printf("The original bill template is : %s\n", str);
//Calling the replacing fucntion
char *newStr = str; //newStr will store the new bill i.e generated
newStr = replaceWord(str, "{{name}}", "Mary");
newStr = replaceWord(newStr, "{{item}}", "Waffle Machine");
newStr = replaceWord(newStr, "{{outlet}}", "Belgium Waffle");
printf("\nThe bill generated is:\n%s", newStr);
fprintf(ptr2, "%s", newStr);
fclose(ptr);
fclose(ptr2);
return 0;
}
Can someone explain why the pointer *str and *resultString are expressed different ways in the program and what are they doing? Sometimes it's *str, &str or str[i].
Please explain.
I know that a pointer is used to keep the address of the other variables but this code is still a mystery to me.
Also why was the function a pointer?
NOTE:"He said that's how it works" when I asked how.
Please help!! I can't focus on other things.
If you can't explain ;a link of explanation would be fine as well.
Sometimes it's *str, &str or str[i]
Those are operators.
*str
str is a poitner to a char, and having a * over it dereferences it. Meaning it fetches the value from the memory that it is pointing to. A pointer may not always point to a variable though, it can be any arbitrary memory address. But dereferencing memory that is not yours will result in Segmentation fault which is the my most beloved error that occurs almost everytime when processing arrays.
str[i]
This is the same as *(str + i). Meaning it increments the memory address by i * sizeof(<datatype of what str points to>). Then it fetches the value from that incremented address. This is used for getting elements of an array.
&str
This just given the address of the variable str, which is a pointer. So, it returns a pointer to a pointer(ie. str). A pointer to a pointer can exist.
The function is not a pointer. Instead, it returns a pointer which is *resultString. It is so that a string can be returned. The string had been initialized in this line:
resultString = (char *)malloc(i + count * (newWordLength - oldWordLength) + 1);
The comment explaining this is not complete.
//dynamically allocation memory to resultString since it can be big or samll depending on the size of the newWord.
/*i = old string length , count = no. of times the word appeared in the string,
newWordLength-oldWordLength=difference between the new word and the old word
+1 for the null character '\0'
Basically we are saying that add the size required for the newWord to the strings length i.e i;
*/
It also misses one key reason why malloc is being used instead of normal allocation. malloc allocates your variables on the heap which is shared among all functions and threads. While normal initialization would allocate it on the stack which is popped off when the function ends. So, no use after the function with the stack, so it should be used on the heap. And it is also for dynamic allocation.
I have a string with the following pattern :
char *str = "ai/aj/module_mat.mod";
and I want to select module_mat as my final string for the further logic. I have tried to used rindex() so that I can get the final part of the string. But I am not able to do this in C. What am I doing wrong?
The code I am trying is -
char *first = rindex(str, "/");
char *first = strtok(first, ".");
Your mistake is right here:
char *str = "ai/aj/module_mat.mod";
Since str points to a constant, this should be:
const char *str = "ai/aj/module_mat.mod";
Now your compiler should show you the other problems.
Similarly:
char *first = rindex(str, "/");
Since rindex is returning a pointer into the constant you passed it, that pointer should also be const.
char *first = strtok(first, ".");
Hmm, what do the docs for strtok say:
If a delimiter byte is found, it is overwritten with a null byte
to terminate the current token, and strtok() saves a pointer to the following byte; ...
So strtok modifies the thing the pointer points to, so passing it a pointer to a constant is bad! You can't modify a constant.
First off, the string literal is immutable, so it is very dangerous to bind it to a mutable char pointer. First fix your code:
const char* str = "ai/aj/module_mat.mod";
Next, use strchr:
#include <string.h>
const char* p = strchr(str, '/');
if (p != NULL) {
++p;
printf("Last part: %s\n", p);
} else {
printf("No '/' found in string %s.\n", str);
}
If a / is found in the string, p will point to it, and hence p can be used as the suffix substring of the original string, and there's no need to modify the original string. We advance p by one to skip past the / and are left with the final part of the string.
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);
I am pretty confused with pointers in C. I am finding it hard to wrap my mind around creating them and passing stuff around? I have a "Segmentation Fault: 11" error after I added code, in which previously it worked. Needed to add something. This is part of the code:
char *token2;
char *line2;
char comma_loc = 0;
int num_of_commas = 0;
char *line2[1];
while(token != NULL) { //lets make sure token has a string token
//printf("Wats in token: %s\n", token);
if(key==true) {
//printf("This should be an identifier: %s\n", token);
if(comma != true) { //added if statement, just take away if it fails, the first case is the original
int len = strlen(token);
iden_holder[iden_holder_count] = (char *)malloc(sizeof(char) * (len +1));
memcpy(iden_holder[iden_holder_count], token, len +1);
iden_holder_count++;
key = false;
} else {
int len2 = strlen(token);
line2[0] = (char *)malloc(sizeof(char) * (len2 + 1));
memcpy(line2[0], token, len2 + 1);
token2 = strtok(line2[0],",");
while(token2 != NULL) {
int len = strlen(token2);
iden_holder[iden_holder_count] = (char *)malloc(sizeof(char) * (len +1));
memcpy(iden_holder[iden_holder_count], token, len +1);
iden_holder_count++;
token2 = strtok(line2[0],",");
}
key = false;
}
Point of this code is to take the string within token and copy it into another token, in my case token2. I decided to use memcpy, but I am confused how to use it due to the pointers confusion. I should also note that I used strtok before this, and the code here is within in. Could it be that if I use it again that it will override the other one?
Read this completely. It will help you with your basics. It did to me. :)
Pointers are exactly that: pointers. They're meant to point to something. The vast majority of problems people have with pointers is that they're not pointing anywhere intelligent :-)
Consider the following code:
char xyzzy[] = "hello";
char *pch;
In a stack-based C implementation, this will probably give you a stack containing the string and a pointer set to an arbitrary value.
The pointer exists on the stack like any other variable but it could point to anywhere.
If you then execute:
pch = xyzzy;
it's set to point to the first character of xyzzy (the h).
Arrays and pointers are very different beasts. For example, you cannot increment xyzzy to point to the second character of that string but you can increment pch.
The confusion arises because, in quite a lot of circumstances, arrays will decay to a pointer to the first element of that array.
That's basically the reason why you don't need [] for pointers, because they're not arrays. They do not know, and do not care, about how many things may exist at the memory they point at, their only concern is the one thing they currently point to.
Moving the pointer throughout the array, and ensuring you don't go off the ends, is extra management that you have to do as a programmer.
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