How to replace a single character in one string with another string? - c

Looking to replace a character of a string with another string. I'd like it to work so that it can be used in the middle of a string and keeps the subsequent characters.
e.g. below would like to alter the string 'AND THE' to be 'ANDSPACETHE', currently outputting 'ANDSPACE' using strstr(). Ideally this could work multiple times in the same string e.g. 'AND THE CAT' --> 'ANDSPACETHESPACECAT'
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
int main ()
{
char str[30] ="AND THE";
char * pch;
pch = strstr(str," ");
if (pch != NULL){
strncpy (pch,"SPACE",6);
}
printf("%s\n",str);
return 0;
}
OUTPUT = ANDSPACE
DESIREDOUTPUT = ANDSPACETHE

You could start with something like this:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
char str[30] = "AND THE";
char strtoinsert[] = "SPACE";
char* pch = strstr(str, " ");
if (pch != NULL) {
// move remaining part of string further in order to make room
memmove(pch + strlen(strtoinsert), pch + 1, strlen(pch));
// copy the string to insert
memcpy(pch, strtoinsert, strlen(strtoinsert));
}
printf("%s\n", str);
return 0;
}
This will replace the first space encountered. With that base you should be able to figure out how to replace all spaces in a string.
Hint 1: repeat the whole thing until no more space is found.
Hint 2: if the string to insert contains spaces, then it's slightly more complicated as you cannot apply simply hint 1.
Hint 3: if you want to replace not just a single character but a whole word, this doesn't work either, you should be able to figure it out.

Related

Reading words into an array of strings?

Currently I'm reading each character from the user and storing it into a char array called str. From there I'm trying to use a pointer to loop through the string until it sees a space, once a space is seen I want to take the characters already and create an array of strings. Is that possible? Reasons why I'm doing this is because I later want to use an execlp function to execute a process after my initial program was executed.
If you want to split the string into tokens separated by delimiters you could use the strtok function.
An example would be:
#include <stdio.h>
#include <string.h>
int main(void)
{
int i, n;
char str[] = "Hello World";
char *token[4], *act_token;
token[0] = strtok(str, " ");
n=1;
while(n<4 && (act_token=strtok(NULL, " ")))
{
token[n] = act_token;
n++;
}
for(i=0;i<n;i++)
{
printf("%d: %s\n", i, token[i]);
}
return 0;
}

How do I deal with multiple spaces before or in between the words in CS50's initials (more comfortable)?

Problem: http://docs.cs50.net/problems/initials/more/initials.html
As I said in the title, I can't seem to get the program to output the initials with no spaces if the user inputs extra spaces before the name or inputs extra spaces between the first and last name.
Right now, it works only if I input my name like:First Last with no spaces before the name and only one space inbetween the two words. It will print out FL without any additional spaces. I want it to do this no matter how many extra spaces I have before or inbetween the first and last name.
My current code:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void) {
printf("Name: ");
string s = get_string();
printf("%c", toupper(s[0]));
for (int i = 0; i < strlen(s); i++) {
if (s[i] == ' ') {
printf("%c", toupper(s[i +1]));
}
}
printf("\n");
}
While you already have a good answer, presuming that string s = get_string(); in the cs50.h world just fills s with a nul-terminated string, and s is either a character array or pointer to allocated memory there are a couple of areas where you may consider improvements.
First, don't use printf to print a single character. That is what putchar (or fputc) is for. (granted a smart optimizing compiler should do it for you, but don't rely on the compiler to fix inefficiencies for you) E.g., instead of
printf("%c", toupper(s[0]));
simply
putchar (toupper(s[0]));
Also, there are some logic issues you may wish to consider. What you want to know is (1) "Is the current character a letter?" (e.g. isalpha (s[x]), (2) "Is this the first character (e.g. index 0), or is it a character that follows a space?" (e.g. s[x-1] == ' '). With than information, you can use a single putchar to output the initials.
Further, with s being a string, you can simply use pointer arithmetic (e.g. while (*s) {.. do stuff with *s ..; s++;}) which ends when you reach the nul-terminator, or if you want to preserve s as a pointer to the first character, or if it is an array, then char *p = s; and operate on p)
Putting those pieces together, you could do something like the following without relying on string.h (you can use simple ifs and bit manipulations of the 6th bit to remove reliance on ctype.h functions as well -- that's for later):
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
int main (void) {
char *p = NULL;
printf ("Name: ");
string s = get_string(); /* assuming this works as it appears */
for (p = s; *p; p++)
/* if current is [a-zA-Z] and (first or follows space) */
if (isalpha (*p) && (p == s || (*(p - 1) == ' ')))
putchar (toupper (*p));
putchar ('\n'); /* tidy up */
return 0;
}
Example Use/Output
$ ./bin/initials
Name: David C. Rankin
DCR
$ ./bin/initials
Name: Jane Doe
JD
$ ./bin/initials
Name: d
D
$ ./bin/initials
Name: George W... Bush
GWB
Don't use strlen in the condition of the for-loop, it will be executed at every single step, better save the value in a variable and use the variable in the condition instead.
I would use in this case strtok, it deals with inputs like Tom marvolo riddle where you have multiple white spaces between the names.
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char line[1024];
fgets(line, sizeof line, stdin);
char *token, *src = line;
while(token = strtok(src, " \t"))
{
src = NULL; // subsequent calls of strtok must be called
// with NULL
printf("%c", toupper(*token));
}
printf("\n");
return 0;
}
When using strtok you have to remember not to pass a string literal ("this is a string literal") because they are read-only and strtok writes a \0 at the position where the delimiter is found. If you don't know if you have write access to buffer, you have to make a copy (either in a static buffer with enough length, or use malloc) and then use the copy in strtok.
In my example I know that line is not a read-only variable, thus I can safely use in strtok (provided that I won't use it any more, otherwise a copy is required).
One problem with strtok is that it is not reentrant and it's better to use strtok_r instead.
char *token, *src = line, *saveptr;
while(token = strtok_r(src, " \t", &saveptr))
...
In order to make your code work, a simple approach is to add a flag telling whether the previous character was a space. Something like:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
int wasSpace = 1; // Add a flag.
printf("Name: ");
string s = get_string();
for (int i = 0; i < strlen(s); i++)
{
if (wasSpace && s[i] != ' ') // Only print if previous was a space and this isn't
{
wasSpace = 0;
printf("%c", toupper(s[i]));
}
else if (s[i] == ' ')
{
wasSpace = 1; // Update the flag
}
}
printf("\n");
return 0;
}

c, delete words which contain digits from a string

I need to delete all words that contain digits from the string.
E.g. if input is abdgh 67fgh 32ghj hj dfg43 11 fg, output should be abdgh hj fg.
I thought of using while( text[i] != ' '), but I don't know how to continue it for the rest of the string (after the first whitespace).
I don't have any other idea, and couldn't find anything by googling. Please, help me!
Here, i gave it a try. Works just fine for me. I tried to explain the logic throughout the code via comments. Hope it helps.
#include <stdio.h>
#include <string.h>
int containsNum(char * str);
int main()
{
char str[] = "abdgh 67fgh 32ghj hj dfg43 11 fg"; // input string
char newstr[100] = ""; //new string to create with filtered data
char * pch; //temp string to use in strtok
printf("given string : %s\n",str );
pch = strtok (str," ");
while (pch != NULL)
{
if(!containsNum(pch))// creation of new string with strcat
{ // if the current word not contains any number
strcat(newstr,pch);
strcat(newstr," "); //adding a space between words for readability
}
pch = strtok (NULL, " ");
}
printf("modified string : %s\n", newstr );
return 0;
}
//function containsNum
//gets a string and checks if it has any numbers in it
//returns 1 if so , 0 otherwise
int containsNum(char * str)
{
int i,
size =strlen(str),
flag=0;
for(i=0; i<size ; ++i)
{
if((int)str[i] >=48 && (int)str[i] <=57 ){
flag =1;
break;
}
}
return flag;
}
Regards
Algorithm:
1-You will have to break your input string into smaller components which are also called as tokens. For example: for the string abdgh 67fgh 32ghj hj dfg43 11 fg the tokens could be abdgh, 67fgh, 32ghj, hj, dfg43, 11 and fg.
2- These smaller strings or tokens can be formed using the strtok function which is defined as
char * strtok ( char * str, const char * delimiters );. Thestr in the first argument is the input sting which in the code presented below is string1. The second argument called the delimiters is what actually defines when to divide the input string into smaller pieces(tokens).
For instance, a whitespace as a delimiter will divide the input string whenever a whitespace is encountered, which is how the string is being divided in the code.
3-Since, your program needs to delete those words in the input string which contain digits we can use the isdigit() function to check exactly that.
WORKING CODE:
#include <cstring>
#include <ctype.h>
#include<stdio.h>
int main ()
{
char output[100]="";
int counter;
int check=0; /* An integer variable which takes the value of "1" whenever a digit
is encountered in one of the smaller strings or tokens.
So, whenever check is 1 for any of the tokens that token is to be ignored, that is,
not shown in the output string.*/
char string1[] = "abdgh 67fgh 32ghj hj dfg43 11 fg";
char delimiters[] = " ";//A whitespace character functions as a delimiter in the program
char * token;//Tokens are the sub-strings or the smaller strings which are part of the input string.
token=strtok(string1,delimiters);/*The first strktok call forms the first token/substring which for the input
given would be abdgh*/
while(token!=NULL)/*For the last substring(token) the strtok function call will return a NULL pointer, which
also indicates the last of the tokens(substrings) that can be formed for a given input string.
The while loop finishes when the NULL pointer is encountered.*/
{
for(counter=0;counter<=strlen(token)-1;counter++)/*This for loop iterates through each token element.
Example: In case of abdgh, it will first check for 'a',
then 'b', then 'd' and so on..*/
{
if(isdigit((int)token[counter])>0)/*This is to check if a digit has been encountered inside a token(substring).
If a digit is encountered we make check equal to 1 and break our loop, as
then that token is to be ignored and there is no real need to iterate
through the rest of the elements of the token*/
{
check=1;
break;
}
}
if(check==1) /* Outside the for loop, if check is equal to one that means we have to ignore that token and
it is not to be made a part of the output string. So we just concatenate(join) an
empty string ( represented by " " )with the output string*/
{
strcat(output,"");
check=0;
}
else /*If a token does not contain any digit we simply make it a part of the output string
by concatenating(joining) it with the output string. We also add a space for clarity.*/
{
strcat(output,token);
strcat(output," ");
}
token = strtok( NULL, delimiters ); /*This line of code forms a new token(substring) every time it is executed
inside the while loop*/
}
printf( "Output string is:: %s\n", output ); //Prints the final result
return 0;
}
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
char *filter(char *str){
char *p, *r;
p = r = str;
while(*r){
char *prefetch = r;
bool contain_digit = false;
while(!isspace(*prefetch) && *prefetch){
if(contain_digit)
++prefetch;
else if(isdigit(*prefetch++))
contain_digit = true;
}
if(contain_digit){
r = prefetch;
}else {
while(r < prefetch){
*p++ = *r++;
}
}
if(!*r)
break;
if(p[-1] == *r)
++r;
else
*p++ =*r++;
}
*p = '\0';
return str;
}
int main(void) {
char text[] = "abdgh 67fgh 32ghj hj dfg43 11 fg";
printf("%s\n", filter(text));//abdgh hj fg
return 0;
}

How to extract a substring from a string in C?

I tried using strncmp but it only works if I give it a specific number of bytes I want to extract.
char line[256] = This "is" an example. //I want to extract "is"
char line[256] = This is "also" an example. // I want to extract "also"
char line[256] = This is the final "example". // I want to extract "example"
char substring[256]
How would I extract all the elements in between the ""? and put it in the variable substring?
Note: I edited this answer after I realized that as written the code would cause a problem as strtok doesn't like to operate on const char* variables. This was more an artifact of how I wrote the example than a problem with the underlying principle - but apparently it deserved a double downvote. So I fixed it.
The following works (tested on Mac OS 10.7 using gcc):
#include <stdio.h>
#include <string.h>
int main(void) {
const char* lineConst = "This \"is\" an example"; // the "input string"
char line[256]; // where we will put a copy of the input
char *subString; // the "result"
strcpy(line, lineConst);
subString = strtok(line,"\""); // find the first double quote
subString=strtok(NULL,"\""); // find the second double quote
printf("the thing in between quotes is '%s'\n", subString);
}
Here is how it works: strtok looks for "delimiters" (second argument) - in this case, the first ". Internally, it knows "how far it got", and if you call it again with NULL as the first argument (instead of a char*), it will start again from there. Thus, on the second call it returns "exactly the string between the first and second double quote". Which is what you wanted.
Warning: strtok typically replaces delimiters with '\0' as it "eats" the input. You must therefore count on your input string getting modified by this approach. If that is not acceptable you have to make a local copy first. In essence I do that in the above when I copy the string constant to a variable. It would be cleaner to do this with a call to line=malloc(strlen(lineConst)+1); and a free(line); afterwards - but if you intend to wrap this inside a function you have to consider that the return value has to remain valid after the function returns... Because strtok returns a pointer to the right place inside the string, it doesn't make a copy of the token. Passing a pointer to the space where you want the result to end up, and creating that space inside the function (with the correct size), then copying the result into it, would be the right thing to do. All this is quite subtle. Let me know if this is not clear!
if you want to do it with no library support...
void extract_between_quotes(char* s, char* dest)
{
int in_quotes = 0;
*dest = 0;
while(*s != 0)
{
if(in_quotes)
{
if(*s == '"') return;
dest[0]=*s;
dest[1]=0;
dest++;
}
else if(*s == '"') in_quotes=1;
s++;
}
}
then call it
extract_between_quotes(line, substring);
#include <string.h>
...
substring[0] = '\0';
const char *start = strchr(line, '"') + 1;
strncat(substring, start, strcspn(start, "\""));
Bounds and error checking omitted. Avoid strtok because it has side effects.
Here is a long way to do this: Assuming string to be extracted will be in quotation marks
(Fixed for error check suggested by kieth in comments below)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char input[100];
char extract[100];
int i=0,j=0,k=0,endFlag=0;
printf("Input string: ");
fgets(input,sizeof(input),stdin);
input[strlen(input)-1] = '\0';
for(i=0;i<strlen(input);i++){
if(input[i] == '"'){
j =i+1;
while(input[j]!='"'){
if(input[j] == '\0'){
endFlag++;
break;
}
extract[k] = input[j];
k++;
j++;
}
}
}
extract[k] = '\0';
if(endFlag==1){
printf("1.Your code only had one quotation mark.\n");
printf("2.So the code extracted everything after that quotation mark\n");
printf("3.To make sure buffer overflow doesn't happen in this case:\n");
printf("4.Modify the extract buffer size to be the same as input buffer size\n");
printf("\nextracted string: %s\n",extract);
}else{
printf("Extract = %s\n",extract);
}
return 0;
}
Output(1):
$ ./test
Input string: extract "this" from this string
Extract = this
Output(2):
$ ./test
Input string: Another example to extract "this gibberish" from this string
Extract = this gibberish
Output(3):(Error check suggested by Kieth)
$ ./test
Input string: are you "happy now Kieth ?
1.Your code only had one quotation mark.
2.So the code extracted everything after that quotation mark
3.To make sure buffer overflow doesn't happen in this case:
4.Modify the extract buffer size to be the same as input buffer size
extracted string: happy now Kieth ?
--------------------------------------------------------------------------------------------------------------------------------
Although not asked for it -- The following code extracts multiple words from input string as long as they are in quotation marks:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char input[100];
char extract[50];
int i=0,j=0,k=0,endFlag=0;
printf("Input string: ");
fgets(input,sizeof(input),stdin);
input[strlen(input)-1] = '\0';
for(i=0;i<strlen(input);i++){
if(input[i] == '"'){
if(endFlag==0){
j =i+1;
while(input[j]!='"'){
extract[k] = input[j];
k++;
j++;
}
endFlag = 1;
}else{
endFlag =0;
}
//break;
}
}
extract[k] = '\0';
printf("Extract = %s\n",extract);
return 0;
}
Output:
$ ./test
Input string: extract "multiple" words "from" this "string"
Extract = multiplefromstring
Have you tried looking at the strchr function? You should be able to call that function twice to get pointers to the first and second instances of the " character and use a combination of memcpy and pointer arithmetic to get what you want.

Arrays in C not working

Well, I declared a global array of chars like this char * strarr[];
in a method I am tokenising a line and try to put everything into that array like this
*line = strtok(s, " ");
while (line != NULL) {
*line = strtok(NULL, " ");
}
seems like this is not working.. How can I fix it?
Thanks
Any number of things could be going wrong with the code you haven't shown us, such as undefined behaviour by strtoking a string constatnt, or getting your parameters wrong when calling the function.
But the most likely problem from the code we can see is the use of *line instead of line, assuming that line is of type char *.
Use the following code as a baseline:
#include <stdio.h>
#include <string.h>
int main (void) {
char str[] = "My name is paxdiablo";
// Start tokenising words.
char *line = strtok (str, " ");
while (line != NULL) {
// Print current token and get next word.
printf ("[%s]\n", line);
line = strtok(NULL, " ");
}
return 0;
}
This outputs:
[My]
[name]
[is]
[paxdiablo]
and should be easily modifiable into something you can use.
Be aware that, if you're trying to save the character pointers returned from strtok (which would make sense for using *line), they are transitory and will not be what you expect after you're done. That's because modifications are made in-place within the source string. You can do it with something like:
#include <stdio.h>
#include <string.h>
int main (void) {
char *word[4]; // The array of words.
size_t i; // General counter.
size_t nextword = 0; // For preventing array overflow.
char str[] = "My name is paxdiablo";
// Start tokenising.
char *line = strtok (str, " ");
while (line != NULL) {
// If array not full, duplicate string to array and advance index.
if (nextword < sizeof(word) / sizeof(*word))
word[nextword++] = strdup (line);
// Get next word.
line = strtok(NULL, " ");
}
// Print out all stored words.
for (i = 0; i < nextword; i++)
printf ("[%s]\n", word[i]);
return 0;
}
Note the specific size of the word array in that code above. The use of char * strarr[] in your code, along with the message tentative array definition assumed to have one element is almost certainly where the problem lies.
If your implementation doesn't come with a strdup, you can get a reasonably-priced one here :-)

Resources