copying an substring to string - c

i'm trying to get a 2 strings from the user and the second one will be the "needle" to copy to the first string
for example:
string 1 (user input): eight height freight
string 2 (user input): eight
output: EIGHT hEIGHT frEIGHT
for example i want to print: toDAY is a good DAY
having trouble copying multiple needles in stack
i have tried using while (*str) {rest of the function with str++}
i would love some explanation
#define _CRT_SECURE_NO_WARNINGS
#define N 101
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
void replaceSubstring(char* str, char* substr);
void main() {
int flag = 1;
char str[N], substr[N];
//char* str_ptr = &str, * substr_ptr = &substr; //creating pointer for the sake of while
while (flag) {
printf("\nEnter main text: ");
gets_s(str,N);
if (!str)
flag = 0;
printf("\nEnter sub-text: ");
gets_s(substr,N);
if (!str)
flag = 0;
replaceSubstring(str, substr);
printf("%s",str);
}
printf("\nExited. (press any key to exit)");
}
void replaceSubstring(char* str, char* substr) {
int lensbstr;
str = strstr(str, substr);
_strupr(substr); //cnvrt to UPPERCASE
lensbstr = strlen(substr); //length of the mutual string
if (str)
strncpy(str, substr, lensbstr);
}

This looks like a programming exercise, so I’m not going to just give you the answer. However, I’ll give you a few hints.
Two big problems:
You don’t have a loop that would replace the second and later instances.
You are upper-casing the substring... not a copy of the substring. A second pass through replaceSubstring would only match the upper-case version of the substring.
A couple of small problems / style comments:
str is an array, so its value is always non-zero, so “if(!str)” is never true.
strncpy is almost never the right answer. It will work here, but you shouldn’t get in the habit of using it. Its behavior is subtle and is rarely what you want. Here it would be faster and more obvious to use memcpy.
You are upper-casing the substring and measuring its length even if you didn’t find it and so won’t need those results.
Although using int for flags works and is the traditional way, newer versions of the language have stdbool.h, the “bool” type, and the “true” and “false” constants. Using those is almost always better.
You appear to intend to stop when the user enters an empty string for the first string. So why do you ask for the second string in that case? It seems like you want an infinite loop and a “break” in the middle.

Related

Edge case in C program to find and replace words from a text file

I'm new to C and would greatly appreciate some help in fixing a bug in my program.
I've identified an edge case and I'm not quite sure how to resolve it.
Currently, the function will find and replace words and words within words given a text file. For instance, changing 'water' to 'snow' will change the string 'waterfall' into 'snowfall'. This is an intended result.
However, when I input 'waterfalls' to change the word 'waterfall', the program seems to get stuck in an endless loop. I'm not quite sure why but I would appreciate if anyone could point me in the right direction.
Here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define BUFFER_SIZE 20
void replaceWord(char *str, const char *oldWord, const char *newWord)
{
char *position, buffer[BUFFER_SIZE];
int index, oldWordLength;
oldWordLength = (long)strlen(oldWord);
while ((position = strstr(str, oldWord)) != NULL)
{
strcpy(buffer, str);
index = position - str;
str[index] = '\0';
strcat(str, newWord);
strcat(str, buffer + index + oldWordLength);
}
}
int main()
{
char msg[100] = "This is some text with the word snowfall to replace";
puts(msg);
replaceWord(msg, "snowfall", "snowfalls");
puts(msg);
return 0;
}
Ok. First, you have a severely undersized buffer. This:
char buffer[BUFFER_SIZE];
is the target of what ends up being a full-string copy of the original message. But in main, the original message:
char msg[100] = "This is some text with the word snowfall to replace";
is 51 characters wide (not including the terminator). That's not going to work, and running through a debug address sanitizer (or a regular debugger, ideally) would show that. :
==1==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd578054d4 at pc 0x7f7457e4c846 bp 0x7ffd57805460 sp 0x7ffd57804c10
WRITE of size 52 at 0x7ffd578054d4 thread T0
#0 0x7f7457e4c845 (/opt/compiler-explorer/gcc-11.2.0/lib64/libasan.so.6+0x55845)
#1 0x4012a7 in replaceWord /app/example.c:15
#2 0x401592 in main /app/example.c:27
#3 0x7f7457c2c0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
#4 0x40112d in _start (/app/output.s+0x40112d)
Address 0x7ffd578054d4 is located in stack of thread T0 at offset 52 in frame
#0 0x4011f5 in replaceWord /app/example.c:9
So that clearly isn't any good. Fixing that by increasing the buffer size will "work", but to really do this right the source/target buffer (in your function they're one in the same) should have its full writable width (and that includes space for a terminator) provided as an argument (which you should definitely do.
Second, the code that does this:
while ((position = strstr(str, oldWord)) != NULL)
is always starting the search for oldWord from the beginning of the input string. that's wrong (well, it's right exactly once; the first time through; after that, it's wrong). Consider this:
i love c++
Suppose I look or i and I want to replace it with is. I would find it here:
i love c++
^
After replacement my new string I'm building looks like this:
is love c++
So where do you know to start the next search from? You start at the position where the original string started, plus the length of the replacement string value. The original was in pos 0. the length of the replacement was 2, so we start the next search at pos 2.
is love c++
^
Note that this gets a LOT more complicated when you're doing everything in-place (e.g. no intermediate buffer), but that doesn't seem to be a goal for you right now, and is likely off your radar. Therefore, a not-very-efficient, but functional way to do this is:
Start at the beginning of the string (src = str)
Search for the old word, starting at src.
If found, copy the original string up-to, but not including, the old word to a buffer.
Append the replacement string to the buffer.
Append the remainder of the original string passed the old word to the buffer.
Copy the buffer back to the source string.
Reposition src to be the length of the replacement word past the original position of the found old word from (3)
Loop back to (2) until the old word is no longer found.
As I said; not very efficient, but it is fairly easy to understand. It looks like this in code. Note the buffer size was significantly increased, and is used to declare both the temp buffer and the array in main. This still isn't good, but it was what you brought, so I'm sticking with it. I urge you to consider doing this algorithm with dynamic memory management, or size-restrictions passed as additional argument(s):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define BUFFER_SIZE 100
void replaceWord(char *str, const char *oldWord, const char *newWord)
{
char buffer[ BUFFER_SIZE ];
char *src = str;
char *oldpos = NULL;
size_t lenOldWord = strlen(oldWord);
size_t lenNewWord = strlen(newWord);
while ((oldpos = strstr(src, oldWord)) != NULL)
{
// 1. copy everything up to the old word.
// 2. append the new word
// 3. copy the remainder of source string *past* the old word
// 4. copy back to the original string.
memcpy(buffer, str, (size_t)(oldpos - str));
memcpy(buffer + (oldpos - str), newWord, lenNewWord);
strcpy(buffer + (oldpos - str) + lenNewWord, oldpos + lenOldWord);
strcpy(str, buffer);
// the new starting point will be the previous discovry
// location plus the length of the new word.
src = oldpos + lenNewWord;
}
}
int main()
{
char msg[BUFFER_SIZE] = "This is some text with the word snowfall to replace";
puts(msg);
replaceWord(msg, "snowfall", "snowfalls");
puts(msg);
return 0;
}
Output
This is some text with the word snowfall to replace
This is some text with the word snowfalls to replace
I strongly suggest you to run this in a debugger and watch how it works, step by step. It will help you understand where you were missing the start-search-here logic. And I urge you even more, as an exercise, address the blatant vulnerability of this algorithm. think of ways you could easily invoke undefined behavior (hint: short, common old word, very very long replacement word), and the things you should to do address those problems.

recursion execution in reverse string

#include <stdio.h>
#define MAX 100
char *reverse(char[]);
int main()
{
char str[MAX], *rev;
enter code here //printf("Enter a String: ");
scanf("%s", str);
rev = reverse(str);
printf("The reversed string is : %s\n", rev);
return 0;
}
char* reverse(char str[])
{
static int i= 0;
static char rev[MAX];
if (*str)
{
reverse(str+1);
rev[i++]= *str;
}
return rev;
}
how is the execution taking place in the function reverse......pls explain each step of the execution with example
thank you
The main point of the function reverse is recursion.
Recursive function as you know, are functions that call themselves from within their own code. Generally, each call got a smaller "problem" than the previous one.
Let's look at the function. We have two static variables that are static so as dxiv said in the comment, they will "keep" their value once they are initialized the first time. But in certain cases, "static" variables are also a problem to deal with.
Now we have an if that check whether we have still some character inside the string or not. That means that if we reach the end of the string, the piece of the code inside the if will not be executed.
Let's look at this example:
I added a printf to check the string content each time and as you see, the function goes to the last element of the string (if we think of it as an array) and once it reaches the end, it starts to do the next instruction.
So the function will call itself, increasing str time by time:
reverse(str + 1);
Once we reach the end of str, the program passes with the following instruction:
assign a char to the reverse array that in this case will start from zero since the counter variable i is still at 0.
The returning value is considered just at the end and not during the recursion "phase".
At this point the game is done, recursion function calls that are on the stack are going to be removed one by one, and each of them now can add the letter at the reverse array. Doing this i will increase and we are considering each time the letter before in the string.
In this way, in the end, we will have the reversed string.
Some tips:
Use fgets(..., ..., ...) instead of scanf so that you can take also sentences instead of just a word let's say. But there are still some other advantages, that I let you discover.
Generally, that returning value should be used also in the recursion process
Personally, I prefer to don't have static variables in a recursive function (unless I really need it). I prefer to have (if it is possible) the variables that I need as parameters.
I'm going to attach the code with fgets(...) right here below:
#include <stdio.h>
#include <string.h>
#define MAX 100
char *reverse(char[]);
int main() {
char str[MAX], *rev;
printf("Enter a String: ");
fgets(str, sizeof(str), stdin);
str[strcspn(str, "\n")] = '\0';
rev = reverse(str);
printf("The reversed string is: %s\n", rev);
return 0;
}
char *reverse(char str[]) {
static int i = 0;
static char rev[MAX];
if (*str) {
reverse(str + 1);
rev[i++] = *str;
printf("\n%s", str);
}
return rev;
}
I really hope that this can help you :D
Best regards,
Denny

How to make a conditional loop from "Yes, no" question by comparing String with pointer initiation? [C Programming]

int main(int argc, char* argv[]) {
char* string; //local variable for a character
string = (char*)malloc(sizeof(char));
char* yes = "yes";
printf("Do you want to play (y/n)?");
scanf_s("%s", string);
if (strcmp(yes, string) == 0) {
printf("Hello welcome...");
}
Above is my code. Essentially, I want to make a loop asking for the user to input yes, y to continue; n, no to discontinue. But I simplify it for the sake of simple codes. The program just output the question, I press enter yes and enter then it stops.
I cant figure out a way to do it using array syntax( char string[] way, although array and malloc are basically the same) so I use pointer and malloc instead.
I'm going mad because this is bugging me so much. The practice assignment only asks to input character 'y' 'n' using %c but i want to do it the %s.
Really appreciate any help, im really stuck now. Thank you so much
Your code has two significant problems. First, if you want to input a string of characters, your malloc call needs to allocate space for more than one character; you should allocate the maximum number of characters you think the user's input will contain plus one - strings in C have a zero (nul) character at the end, to mark the end of the string).
Second, when you use the scanf_s function to read in a string (using the %s format specifier, as you have done), then you need to add additional parameters (the size of the target string buffer) after each string argument.
Here's a modified version of your code with these (and a few other) corrections:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
char* string = malloc(5); //local variable for a character string (up to 5 chars)
char* yes = "yes";
printf("Do you want to play (y/n)?");
scanf_s("%s", string, 5);
if (strcmp(yes, string) == 0) {
printf("Hello welcome...");
}
free(string); // Don't forget to release the memory!
return 0; // Conventionally, return 0 for success or non-zero on error
}
Note 1: Each and every call to malloc (or calloc) should be paired with a call to free to release the allocated memory, or you will end up with memory leaks.
Note 2: Please read this post: Do I cast the result of malloc?
Note 3: Although most (all?) C compilers will not insist on it, it is good practice to explicitly add a return 0; (for success) statement at the end of the main function.
Please feel free to ask for any further clarification and/or explanation.

The basics of using strings and substrings in C programming [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I've been trying to learn C programming by reading a textbook, but am confused about how strings and substrings work.
I have an idea of what strings and substrings are from java, but can't figure out the syntax in C.
Here's a question from the book that I thought might be easy, but I can't get it.
Write and test a function hydroxide that returns a 1 for true if its string argument ends in the substring OH.
It recommends testing the function with KOH and NaCl.
Also, how would I remove and add letters at the end of the string?
Like, if for some reason I wanted to change NaCl to NaOH?
Any help and explanations would be really appreciated.
ETA:
I guess what I'm most confused on is how to make the program look at the last two letters in the string and compared them to OH.
I'm also not sure how to pass strings to functions.
String is a sequence of characters that ends with special null-terminated character '\0'. If there is no \0, functions that work with string won't stop until the \0 symbol is found. This character may happen in any place after the end of pseudo string (I mean a string without \0) and only then stop.
The following example shows the necessity of this null-terminated character:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char string[] = "Hello!";
printf("original string:\n%s\n\n", string);
memset(string, '-', 5);
printf("memset doesn't affect the last two symbols: '!' and '\\0':\n%s", string);
memset(string, '-', 6);
printf("\n\nmemset doesn't affect the last symbol: '\\0':\n%s\n\n", string);
memset(string, '-', 7);
printf("memset affects all symbols including null-terminated one:\n%s", string);
return 0;
}
/* OUTPUT:
original string:
Hello!
memset doesn't affect the last two characters: '!' and '\0':
-----!
memset doesn't affect the last character: '\0':
------
memset affects all characters including null-terminated one:
-------#↓#
*/
Substring is a char sequence that is in a string. It may be less or equal to the string.
Suppose, "NaOH" is a string. Then substring may be: "N", "a", "O", "H", "Na", "aO", "OH", "NaO", "aOH", "NaOH". To find whether substring is in the string or not you can use strstr function. It's prototype is char * strstr ( char * str1, const char * str2 );.
This code shows this function's results:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *ptrCh = NULL;
ptrCh = strstr("hello", "h");
printf("ptrCh: %p\n", ptrCh);
printf("%s\n\n", ptrCh);
ptrCh = strstr("hello", "z");
printf("ptrCh: %p\n", ptrCh);
printf("%s\n\n", ptrCh);
return 0;
}
/* OUTPUT:
ptrCh: 00403024
hello
ptrCh: 00000000
(null)
*/
As for the first printf, it prints characters beginning from the position of 'h' and when it reaches null-terminated character, which is next after 'o', it stops, exactly as in previous program.
To make your program more interactive, you can declare array and then a pointer to it. Array size must be enough to store the longest formula. Suppose, 100 will be enough:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buf[100] = {0};
char *ptr = &buf[0];
scanf("%s", ptr);
// printf() gets a pointer as argument
printf("%s\n", ptr);
// printf() gets also a pointer as argument.
// When you pass arrays name without index to a function,
// you pass a pointer to array's first element.
printf("%s", buf);
return 0;
}
And as for rewriting letters in the end of the string. Here is a small program that does it. Pay attention at comments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buf[100] = {0};
char formula[100] = {0};
char compound[100] = {0};
char *ptr = &buf[0];
char *pFormula = &formula[0];
char *pCompound = &compound[0];
printf("Enter formula: ");
scanf("%s", pFormula);
printf("Enter chemical compound: ");
scanf("%s", pCompound);
// Copying the first chemical elements without the last
// several that will be replaced by another elements.
strncpy(ptr, pFormula, strlen(pFormula) - strlen(pCompound));
// Adding new compound to the first elements.
// Function also adds a null-terminated character to the end.
strncat(ptr, pCompound, strlen(pCompound));
printf("The new chemical compound is: ");
printf("%s", ptr);
return 0;
}
/* OUTPUT:
Enter formula: NaOH
Enter chemical compound: Cl
The new chemical compound is: NaCl
*/
In C, we use null-terminated strings. That is the "invisible", 0 value. Not ASCII "0", but the zero value, like 8-bit 0x00. You can represent it in literal text with '\0' or "\0" or unquoted 0, however, in a literal string it is redundant because most functions like strcmp() or strstr() or strcat() all expect and work with null terminated strings. Null char is the stops sign for the C standard string functions.
One easy way to implement this with C library calls is to test for existence of the substring and then test that substring's length, which verify it is at end of string.
Assume buf is some big string buffer, char buf[1024] and char *temp is a temporary variable.
temp = strstr(buf, "OH") returns the pointer to "OH" if exists in buf at any offset.
strlen(temp) Get length of temp, if at end of string, it will be 2 (doesn't include null terminator), so if the original string is "OHIO" or "SOHO" it wont match because it'll be 4 and 3 respectively.
The above is the core of the code, not the full robust implementation. You need to check for valid return values, etc.
char buf[1024];
char *temp;
strcpy(buf, "NaOH");
if((temp = strstr(buf, "OH")) != 0)
{
// At this point we know temp points to something that starts with "OH"
// Now see if it is at the end of the string
if(strlen(temp) == 2)
return true; // For C99 include stdbool.h
return false;
}
You could get obscure, and check for the null terminator directly, will be a smidge quicker. This code is safe as long as it is inside the if() for strstr(), otherwise never do this if you don't know a string is a least N characters long.
if(temp[2] == '\0')
return true; // For C99 include stdbool.h
As far as appending to a string, read the docs on strcat. Keep in mind with strcat, you must have enough space already in the buffer you are appending into. It isn't like C++ std::string or Java/C# string where those will dynamically resize as needed. In C, you get to do all of that yourself.

C homework - string loops replacements

I know it's a little unorthodox and will probably cost me some downvotes, but since it's due in 1 hour and I have no idea where to begin I thought I'd ask you guys.
Basically I'm presented with a string that contains placeholders in + form, for example:
1+2+5
I have to create a function to print out all the possibilities of placing different combinations of any given series of digits. I.e. for the series:
[9,8,6] // string array
The output will be
16265
16285
16295
18265
18285
18295
19265
19285
19295
So for each input I get (number of digits)^(number of placeholders) lines of output.
Digits are 0-9 and the maximum form of the digits string is [0,1,2,3,4,5,6,7,8,9].
The original string can have many placeholders (as you'd expect the output can get VERY lengthly).
I have to do it in C, preferably with no recursion. Again I really appreciate any help, couldn't be more thankful right now.
If you can offer an idea, a simplified way to look at solving this, even in a different language or recursively, it'd still be ok, I could use a general concept and move on from there.
It prints them in different order, but it does not matter. and it's not recursive.
#include <stdlib.h>
#include <stdio.h>
int // 0 if no more.
get_string(char* s, const char* spare_chr, int spare_cnt, int comb_num){
for (; *s; s++){
if (*s != '+') continue;
*s = spare_chr[comb_num % spare_cnt];
comb_num /= spare_cnt;
};
return !comb_num;
};
int main(){
const char* spare_str = "986";
int num = 0;
while (1){
char str[] = "1+2+5";
if (!get_string(str, spare_str, strlen(spare_str), num++))
break; // done
printf("str num %2d: %s\n", num, str);
};
return 0;
};
In order to do the actual replacement, you can use strchr to find the first occurrence of a character and return a char * pointer to it. You can then simply change that pointer's value and bam, you've done a character replacement.
Because strchr searches for the first occurrence (before a null terminator), you can use it repeatedly for every value you want to replace.
The loop's a little trickier, but let's see what you make of this.

Resources