Search and Replace Program Only Printing Original String? - c

I have a project assignment for class and this is what it wants (in C)
Description
Write a program that simulates the search-and-replace operation in a text editor. The program is to have
only three function calls in “main”. The first function prompts the user to type a string of less than 80
characters. It then prompts the user to type the search substring of 10 or fewer characters. Finally, it
prompts the user to type the replace substring of 10 or fewer characters.
The second call is the search-and-replace function, which replaces all occurences of the search
substring with the replace substring and creates a new string. If no occurrences are found, it returns the
original string. Theoretically, the new string could be 800 characters long (80 identical characters
replaced by 10 characters each). Your function must be able to handle overflow by using the “realloc”
function to extend the new string when necessary. (Start with an output string of 80 characters and
extend by 80 as necessary.) The search-and-replace function returns the address of the new string.
After the search-and-replace function returns, a print function prints the resulting string as a series of 80 character lines. If performs word-wrap. That is, a line can end only at a space. If there is no space in 80 characters, then print 79 characters and a hyphen, and continue on the next line.
Write each called function using good structured programming techniques. It is expected to call subfunctions as necessary.
Run the program at least three times:
a. First, run it with no substitutions in the original input.
b. Second, run it with two or more substitutions.
c. Finally, run it with substitutions that cause the output to be at least three lines, one of which
requires a hyphen.
//this is what I have. it works but for some reason it only prints the original string for question c. ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void meow();
void modify();
void print();
char r[10];
char str[80];
char s[10];
char ans[800];
int main() {
meow();
modify();
print();
return 0;
}
void meow() {
printf("\nEnter a string max 80 chars \n");
fgets(str, 80, stdin);
printf("\nEnter a search string max 10 chars \n");
fgets(s, 10, stdin);
printf("\nEnter a replace string max 10 chars \n");
fgets(r, 10, stdin);
}
void modify()
{
int i;
int j;
int c;
int m;
int k;
i = 0;
m = 0;
c = 0;
j = 0;
k = 0;
while ((str[c]) != '\0') {
//if (str[m] == s[i]) {
if (str[m] == s[i]) {
i++;
m++;
if (s[i] == '\0') {
for (k = 0; r[k] != '\0'; k++, j++) {
ans[j] = r[k];
i = 0;
c = m;
}
}
}
//}
else {
ans[j] = str[c];
j++;
c++;
m = c;
i = 0;
}
//}
ans[j] = '\0';
}
}
void print() {
int i, ansl;
ansl = strlen(ans);
if (ansl > 80) {
for (i = 0;i < 80;i++) {
printf("%c", ans[i]);
printf("-\n");
}
}
else {
printf("%s\n", ans);
}
}

Related

I want to print out the text with the most number of times entered

#include <stdio.h>
#include <string.h>
int main() {
char str[100];
int h[26]={0};
int i, j, count, tmp=0;
scanf("%s", str);
count=strlen(str);
for(i=0; i<count; i++) {
h[str[i]-97]++;
}
for(j=0; j<25; j++) {
if(h[j]<h[j+1]) {
tmp=j+1;
}
}
printf("%c", (char)tmp+97);
}
I want to output the most frequently entered lowercase letters, but how can I change it by output the strange values?
Try input this code "aaaabbbbsefa", then the "s" will be output.
Your code has a lot of problems. And a good bit of traps.
scanf("%s", str);
What if the input is longer than str can hold?
count=strlen(str);
This is a waste of cpu cycles. You don't need the length of a string to loop through it, you can simply check if the current element of the string is a \0
for(i=0; i<count; i++) {
h[str[i]-97]++;
}
This is problematic, what if the input contained some other character than lower case characters, this could easily cause out of bounds reading.
for(j=0; j<25; j++) {
if(h[j]<h[j+1]) {
tmp=j+1;
}
}
Firstly, this loop stops before 25, but it should stop before 26
Secondly, this definitely does not do what you think it does.
If you want to print the most frequent lower case character from in your input, this is how the flow should look like-
Take the string input and store it into a char array, make sure it can actually hold it
Declare a variable to keep track of the number of occurrences for each lowercase alphabet
Loop through the input string
Check if the current element is lowercase - if it is, add to the counter - if it isn't, do nothing
Loop through the occurrences record, check if the current occurrence is higher than the highest record (which is set to 0 before the loop) - if it higher, change the highest record to it and store the character - if it isn't, move on
Print the resulting character
This is how that'd look like in C-
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define ALPHABET_COUNT 26
#define MAX_LEN 100
int main()
{
char str[MAX_LEN];
int occurrences[ALPHABET_COUNT] = { 0 };
if (!fgets(str, MAX_LEN, stdin))
{
// Something went wrong, error handling here
return 1;
}
for (int i = 0; str[i] != '\0'; i++)
{
if (islower(str[i]))
{
occurrences[str[i] - 'a']++;
}
}
int highest_occurrence = 0;
char highest_occurring_char;
for (int i = 0; i < ALPHABET_COUNT; i++)
{
if (occurrences [i] > highest_occurrence)
{
highest_occurrence = occurrences[i];
// Convert the current index to its corresponding lowercase alphabet
highest_occurring_char = (char) (i + 'a');
}
}
printf("Highest occurring character: %c\n", highest_occurring_char);
}

Manipulating dynamically allocated 2D char arrays in C

I'm having trouble with trying to manipulate 2d dynamic arrays in C. What I want to do is to store a char string in every row of the the 2d array then perform a check to see if the string contains a certain character, if so remove all occurrences then shift over the empty positions. What's actually happening is I get an exit status 1.
More about the problem, for example if I have
Enter string 1: testing
Enter string 2: apple
Enter string 3: banana
I would want the output to become
What letter? a // ask what character to search for and remove all occurences
testing
pple
bnn
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
void removeOccurences2(char** letters, int strs, int size, char letter){
// Get size of array
// Shift amount says how many of the letter that we have removed so far.
int shiftAmt = 0;
// Shift array says how much we should shift each element at the end
int shiftArray[strs][size];
// The first loop to remove letters and put things the shift amount in the array
int i,j;
for(i=0;i < strs; i++){
for(j = 0; j < size - 1; j++) {
if (letters[i][j] == '\0'){
break;
}
else {
// If the letter matches
if(letter == letters[i][j]){
// Set to null terminator
letters[i][j] = '\0';
// Increase Shift amount
shiftAmt++;
// Set shift amount for this position to be 0
shiftArray[i][j] = 0;
}else{
// Set the shift amount for this letter to be equal to the current shift amount
shiftArray[i][j] = shiftAmt;
}
}
}
}
// Loop back through and shift each index the required amount
for(i = 0; i < strs; i++){
for(j = 0; j < size - 1; j++) {
// If the shift amount for this index is 0 don't do anything
if(shiftArray[i][j] == 0) continue;
// Otherwise swap
letters[i][j - shiftArray[i][j]] = letters[i][j];
letters[i][j] = '\0';
}
//now print the new string
printf("%s", letters[i]);
}
return;
}
int main() {
int strs;
char** array2;
int size;
int cnt;
int c;
char letter;
printf("How many strings do you want to enter?\n");
scanf("%d", &strs);
printf("What is the max size of the strings?\n");
scanf("%d", &size);
array2 = malloc(sizeof(char*)*strs);
cnt = 0;
while (cnt < strs) {
c = 0;
printf("Enter string %d:\n", cnt + 1);
array2[cnt] = malloc(sizeof(char)*size);
scanf("%s", array2[cnt]);
cnt += 1;
}
printf("What letter?\n");
scanf(" %c", &letter);
removeOccurences2(array2,strs,size,letter);
}
Thanks in advance!
You can remove letters from a string in place, because you can only shorten the string.
The code could simply be:
void removeOccurences2(char** letters, int strs, int size, char letter){
int i,j,k;
// loop over the array of strings
for(i=0;i < strs; i++){
// loop per string
for(j = 0, k=0; j < size; j++) {
// stop on the first null character
if (letters[i][j] == '\0'){
letters[i][k] = 0;
break;
}
// If the letter does not match, keep the letter
if(letter != letters[i][j]){
letters[i][k++] = letters[i][j];
}
}
//now print the new string
printf("%s\n", letters[i]);
}
return;
}
But you should free all the allocated arrays before returning to environment, and explicitely return 0 at the end of main.
Well, there are several issues on your program, basically you are getting segmentation fault error because you are accessing invalid memory which isn't allocated by your program. Here are some issues I found:
shiftAmt isn't reset after processing/checking each string which lead to incorrect value of shiftArray.
Values of shiftArray only set as expected for length of string but after that (values from from length of each string to size) are random numbers.
The logic to delete occurrence character is incorrect - you need to shift the whole string after the occurrence character to the left not just manipulating a single character like what you are doing.
1 & 2 cause the segmentation fault error (crash the program) because it causes this line letters[i][j - shiftArray[i][j]] = letters[i][j]; access to unexpected memory. You can take a look at my edited version of your removeOccurences2 method for reference:
int removeOccurences2(char* string, char letter) {
if(!string) return -1;
int i = 0;
while (*(string+i) != '\0') {
if (*(string+i) == letter) {
memmove(string + i, string + i + 1, strlen(string + i + 1));
string[strlen(string) - 1] = '\0'; // delete last character
}
i++;
}
return 0;
}
It's just an example and there is still some flaw in its logics waiting for you to complete. Hint: try the case: "bananaaaa123"
Happy coding!
"...if the string contains a certain character, if so remove all occurrences then shift over the empty positions."
The original string can be edited in place by incrementing two pointers initially containing the same content. The following illustrates.:
void remove_all_chars(char* str, char c)
{
char *pr = str://pointer read
char *pw = str;//pointer write
while(*pr)
{
*pw = *pr++;
pw += (*pw != c);//increment pw only if current position == c
}
*pw = '\0';//terminate to mark last position of modified string
}
This is the cleanest, simplest form I have seen for doing this task. Credit goes to this answer.

A program that prints even and odd characters from a string

This is for Homework
I have to write a program that asks the user to enter a string, then my program would separate the even and odd values from the entered string. Here is my program.
#include <stdio.h>
#include <string.h>
int main(void) {
char *str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s", &str);
while (&str[i] < 41) {
if (i % 2 == 0) {
odd[j++] = *str[i];
} else {
even[k++] = *str[i];
}
i++;
}
printf("The even string is:%s\n ", even);
printf("The odd string is:%s\n ", odd);
return 0;
}
When I try and compile my program I get two warnings:
For my scanf I get "format '%s' expects arguments of type char but argument has 'char * (*)[41]". I'm not sure what this means but I assume it's because of the array initialization.
On the while loop it gives me the warning that says comparison between pointer and integer. I'm not sure what that means either and I thought it was legal in C to make that comparison.
When I compile the program, I get random characters for both the even and odd string.
Any help would be appreciated!
this declaration is wrong:
char *str[41];
you're declaring 41 uninitialized strings. You want:
char str[41];
then, scanf("%40s" , str);, no & and limit the input size (safety)
then the loop (where your while (str[i]<41) is wrong, it probably ends at once since letters start at 65 (ascii code for "A"). You wanted to test i against 41 but test str[i] against \0 instead, else you get all the garbage after nul-termination char in one of odd or even strings if the string is not exactly 40 bytes long)
while (str[i]) {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
if you want to use a pointer (assignement requirement), just define str as before:
char str[41];
scan the input value on it as indicated above, then point on it:
char *p = str;
And now that you defined a pointer on a buffer, if you're required to use deference instead of index access you can do:
while (*p) { // test end of string termination
if (i % 2 == 0) { // if ((p-str) % 2 == 0) { would allow to get rid of i
odd[j++] = *p;
} else {
even[k++] = *p;
}
p++;
i++;
}
(we have to increase i for the even/odd test, or we would have to test p-str evenness)
aaaand last classical mistake (thanks to last-minute comments), even & odd aren't null terminated so the risk of getting garbage at the end when printing them, you need:
even[k] = odd[j] = '\0';
(as another answer states, check the concept of even & odd, the expected result may be the other way round)
There are multiple problems in your code:
You define an array of pointers char *str[41], not an array of char.
You should pass the array to scanf instead of its address: When passed to a function, an array decays into a pointer to its first element.
You should limit the number of characters read by scanf.
You should iterate until the end of the string, not on all elements of the array, especially with (&str[i] < 41) that compares the address of the ith element with the value 41, which is meaningless. The end of the string is the null terminator which can be tested with (str[i] != '\0').
You should read the characters from str with str[i].
You should null terminate the even and odd arrays.
Here is a modified version:
#include <stdio.h>
int main(void) {
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
if (scanf("%40s", str) != 1)
return 1;
while (str[i] != '\0') {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = even[k] = '\0';
printf("The even string is: %s\n", even);
printf("The odd string is: %s\n", odd);
return 0;
}
Note that your interpretation of even and odd characters assumes 1-based offsets, ie: the first character is an odd character. This is not consistent with the C approach where an even characters would be interpreted as having en even offset from the beginning of the string, starting at 0.
Many answers all ready point out the original code`s problems.
Below are some ideas to reduce memory usage as the 2 arrays odd[], even[] are not needed.
As the "even" characters are seen, print them out.
As the "odd" characters are seen, move them to the first part of the array.
Alternative print: If code used "%.*s", the array does not need a null character termination.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[41];
printf("Enter a string (40 characters maximum): ");
fflush(stdout);
if (scanf("%40s", str) == 1) {
int i;
printf("The even string is:");
for (i = 0; str[i]; i++) {
if (i % 2 == 0) {
str[i / 2] = str[i]; // copy character to an earlier part of `str[]`
} else {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:%.*s\n ", (i + 1) / 2, str);
}
return 0;
}
or simply
printf("The even string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 != 0) {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 == 0) {
putchar(str[i]);
}
}
printf("\n");
here is your solution :)
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s" , str);
while (i < strlen(str))
{
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = '\0';
even[k] = '\0';
printf("The even string is:%s\n " , even);
printf("The odd string is:%s\n " , odd);
return 0;
}
solved the mistake in the declaration, the scanning string value, condition of the while loop and assignment of element of array. :)

Program that checks if an array is a palindrome

I'm trying to create a program that checks if a given array/string is a palindrome or not and its not working. The program just prints "0" on every given array, even on palindromes.
int main()
{
char string[100]= {0};
char stringReverse[100]= {0};
int temp = 0;
int firstLetter = 0;
int lastLetter = 0;
printf("Please enter a word or a sentence: ");
fgets(string, 100, stdin);
strcpy(stringReverse , string); // This function copies the scanned array to a new array called "stringReverse"
firstLetter = 0;
lastLetter = strlen(string) - 1; //because in array, the last cell is NULL
// This while reverses the array and insert it to a new array called "stringReverse"
while(firstLetter < lastLetter)
{
temp = stringReverse[firstLetter];
stringReverse[firstLetter] = stringReverse[lastLetter];
stringReverse[lastLetter] = temp;
firstLetter++;
lastLetter--;
}
printf("%s %s", stringReverse, string);
if ( strcmp(stringReverse , string) == 0)
{
printf("1");
}
else
{
printf("0");
}
}
Lets say we implement a simple fun to do that
int check_palindrome (const char *s) {
int i,j;
for (i=0,j=strlen(s)-1 ; i<j ; ++i, --j) {
if (s[i] != s[j]) return 0; // Not palindrome
}
return 1; //Palindrome
}
I think this is far more simpler ;)
For the code posted in question:
Be aware of fgets(). It stops in the first '\n' or EOF and keeps the '\n' character.
So if you give radar for ex, the result string will be "radar\n", which doesn't match with "\nradar"
The Problem:
Let's say you enter the string RACECAR as input for your program and press enter, this puts a newline character or a '\n' in your buffer stream and this is also read as part of your string by fgets, and so your program effectively ends up checking if RACECAR\n is a palindrome, which it is not.
The Solution:
After you initialize lastLetter to strlen(string) - 1 check if the last character in your string (or the character at the lastLetter index is the newline character (\n) and if so, decrease lastLetter by one so that your program checks if the rest of your string (RACECAR) is a palindrome.
lastLetter = strlen(string) - 1; //because in array, the last cell is NULL
// Add these 2 lines to your code
// Checks if the last character of the string read by fgets is newline
if (string[lastLetter] == '\n')
lastLetter--;
fgets adds a '\n' at the end.
So if the user entered "aba", string contains "aba\n".
reverseString contains "\naba".
So it doesn't match.
After the fgets, add this code
int l = strlen(string) - 1;
string[l] = 0;
This will strip out the '\n' at the end before copying it to reverseString.
That aside, you can do this whole program inplace without the need of a second buffer or strcpy or strlen calls.
You have several issues in your code:
first you forgot the last closing brace };
then you forgot to remove the trailing \n (or maybe also \r under Windows) in string;
you don't need to revert the string into a new string; a one-pass check is enough:
Here is a working code:
#include <stdio.h>
#include <string.h>
int main()
{
char string[100]= {0};
int temp = 0;
int firstLetter = 0;
int lastLetter = 0;
printf("Please enter a word or a sentence: ");
fgets(string, 100, stdin);
firstLetter = 0;
lastLetter = strlen(string) - 1; //because in array, the last cell is NULL
while ((string[lastLetter]=='\n')||(string[lastLetter]=='\r')) {
lastLetter--;
}
// This while reverses the array and insert it to a new array called "stringReverse"
temp = 1;
while(firstLetter < lastLetter)
{
if (string[firstLetter] != string[lastLetter]) {
temp = 0;
break;
}
firstLetter++;
lastLetter--;
}
if ( temp )
{
printf("1");
}
else
{
printf("0");
}
}
You can do it by this simpleway also.
#include <stdio.h>
#include <string.h>
int main()
{
char string[10], revString[10];
printf("Enter string for reversing it...\n");
scanf("%s", string);
int stringLength = strlen(string);
for(int i = 0; string[i] != '\0'; i++, stringLength--)
{
revString[i] = string[stringLength - 1];
}
if(strcmp(string, revString) == 0)
printf("Given string is pelindrom\n");
else
printf("Given string is not pelindrom\n");
}
#include<stdio.h>
#include<string.h>`enter code here`
void fun(char *a);
int main ()
{
char p[100];
char *s=p;
printf("enter the string");
scanf("%[^\n]",s);
fun(s);
}
void fun(char *a)
{
if(*a && *a!='\n')
{
fun(a+1);
putchar(*a);
}
}
// use this approach better time complexity and easier work hope this helps

C Programming: Counting word length occurences in a string

How would you be able to count word lengths and output their occurrences from a string using gets() or fgets()? For example, here is code doing so but using getchar()below. I think writing it in gets() would make it easier to incorporate all of the delimiters in the program rather than having to manually set if statements for each one of those would it not?
#include <string.h>
#include <ctype.h>
const char delim[] = ", . - !*()&^%$##<> ? []{}\\ / \"";
#define SIZE 100
int main(void){
int length[SIZE] = { 0 };
int name[SIZE];
int i = 0, ch, word_len = 0;
int count = 0;
printf("enter sentence: ");
while (1){
ch = getchar();
if (isalpha(ch)){
++word_len;
}
else if (ch == ' ' || ch == '.'){
if (word_len)
length[word_len - 1]++;//-1: to 0 origin
if (ch == '.')
break;
word_len = 0;
}
}
printf("Word Length \tCount \n");
for (i = 0; i<sizeof(length) / sizeof(*length); ++i){
if (length[i])
printf(" %d \t\t%d\n", i + 1, length[i]);
}
return 0;
}
You can build your custom delimiter detection function.
// globals
const char *delim = " .,;:!?\n\0";
const int n_delim = 9;
int is_delim(int c)
{
register int i;
for (i = 0; i < n_delim; i++)
if (c == delim[i]) return 1;
return 0;
}
This function will return 1 every time it can match c with delim. So you can use it like this:
fgets(buffer, 200, stdin);
for (i = 0; i < strlen(buffer); i++) {
if (is_delim(buffer[i])) {
wl[words++] = length;
length = 0;
continue;
}
length++;
}
I'm assuming you're familiar with the fgets function.
You basically will loop through your buffer, making comparisons with each character. Every loop iteration you check if the current character is a word delimiter, if it is, you save the current length and set length=0 for a new word, and at every iteration you increment the length.
You'll need to come up with a way of either not inserting the zero length values due to double delimiters or just ignore them when you're printing the results.
Basically you want to split a string into words, based on some delimiters, and compute their length. The C standard library provides the strtok function, which does exactly what you need: it splits the given string into multiple tokens.

Resources