remove characters of a char array - c

In the str char array below I would first like to locate the first math symbol I see, then I would like to count backwards and remove whatever is between the previous three "_" and remove the three "_". Can I please get some ideas on how to do this?
So this:
xa_55_y_*_z_/_+_x_+
Should turn into:
xa*_z_/_+_x_+
My problem is I don't know how to remove:
_55_y_
Here is the code so far.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
char str [] = "xa_55_y_*_z_/_+_x_+";
int length = 0;
int decrementor = 0;
int underscore_counter = 0;
int i = 0;
length = strlen (str);
for(i = 0; i < length; i++)
{
decrementor = 0;
underscore_counter = 0;
if(str[i] == '*' || str[i] == '/' || str[i] == '+' || str[i] == '-')
{
decrementor = i;
while(underscore_counter != 3)
{
if(str[decrementor] == '_')
{
underscore_counter++;
printf("underscore_counter is %d \n", underscore_counter);
}
decrementor--;
}
}
}
return 0;
}

You can use strcspn() to find the first operator, which simplifies the problem a little. Then it's just a matter of going backwards and counting the underscores, and then just a matter of outputting the appropriate substrings, e.g.:
int main()
{
char str [] = "xa_55_y_*_z_/_+_x_+";
size_t firstOp = strcspn(str, "*/+-");
size_t len = strlen(str);
size_t i = firstOp;
int underscores = 0;
// go backwards looking for the underscores (or the beginning of the
// string, whichever occurs first)
while (i > 0)
{
if (str[--i] == '_')
underscores++;
if (underscores == 3)
break;
}
// output the first part of the string up to the third underscore
// before the first operator
for (size_t j = 0; j < i; j++)
putchar(str[j]);
// output the rest of the string after and including the operator
for (size_t j = firstOp; j < len; j++)
putchar(str[j]);
// and a linefeed character (optional)
putchar('\n');
}
Sorry for the poorly named i and j variables, hopefully it makes sense.

Related

Counting occurrences of words within an inputted string in c

I'm currently struggling with counting the occurrences of the words within an inputted string. I believe it is just my logic that is off but I've been scratching my head for a while and I've just hit a wall.
The problems I'm currently yet to solve are:
With longer inputs the ends of the string is sometimes cut off.
Incrementing the counter for each word when repeated
I know the code has things that may not be the most ideal way for it to work but I'm fairly new to C so any pointers are really helpful.
To sum it up I'm looking for pointers to help solve the issues I'm facing above
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#define MAX_WORDS 1000
int main(void) {
int i,j,isUnique,uniqueLen;
char word[MAX_WORDS];
char words[200][30];
char uniqueWords[200][30];
int count[200];
char *p = strtok(word, " ");
int index=0;
//read input until EOF is reached
scanf("%[^EOF]", word);
//initialize count array
for (i = 0; i < 200; i++) {
count[i] = 0;
}
//convert lower case letters to upper
for (i = 0; word[i] != '\0'; i++) {
if (word[i] >= 'a' && word[i] <= 'z') {
word[i] = word[i] - 32;
}
}
//Split work string into an array and save each token into the array words
p = strtok(word, " ,.;!\n");
while (p != NULL)
{
strcpy(words[index], p);
p = strtok(NULL, " ,.;!\n");
index++;
}
/*
Check each string in the array word for occurances within the uniqueWords array. If it is unique then
copy the string from word into the unique word array. Otherwise the counter for the repeated word is incremented.
*/
uniqueLen = 0;
for (i = 0; i < index; i++) {
isUnique = 1;
for (j = 0; j < index; j++) {
if (strcmp(uniqueWords[j],words[i])==0) {
isUnique = 0;
break;
}
else {
}
}
if (isUnique) {
strcpy(uniqueWords[uniqueLen], words[i]);
count[uniqueLen] += 1;
uniqueLen++;
}
else {
}
}
for (i = 0; i < uniqueLen; i++) {
printf("%s => %i\n", uniqueWords[i],count[i]);
}
}
This is the code i ended up using, this turned out to be mainly an issue with using the scanf function. Placing it in a while loop made it much easier to edit words as inputted.
Thankyou for all the help :)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int main(void) {
// Create all variables
int i, len, isUnique, index;
char word[200];
char uniqueWords[200][30];
int count[200];
// Initialize the count array
for (i = 0; i < 200; i++) {
count[i] = 0;
}
// Set the value for index to 0
index = 0;
// Read all words inputted until the EOF marker is reached
while (scanf("%s", word) != EOF) {
/*
For each word being read if the characters within it are lowercase
then each are then incremented into being uppercase values.
*/
for (i = 0; word[i] != '\0'; i++) {
if (word[i] >= 'a' && word[i] <= 'z') {
word[i] = word[i] - 32;
}
}
/*
We use len to find the length of the word being read. This is then used
to access the final character of the word and remove it if it is not an
alphabetic character.
*/
len = strlen(word);
if (ispunct(word[len - 1]))
word[len - 1] = '\0';
/*
The next part removes the non alphabetic characters from within the words.
This happens by incrementing through each character of the word and by
using the isalpha and removing the characters if they are not alphabetic
characters.
*/
size_t pos = 0;
for (char *p = word; *p; ++p)
if (isalpha(*p))
word[pos++] = *p;
word[pos] = '\0';
/*
We set the isUnique value to 1 as upon comparing the arrays later we
change this value to 0 to show the word is not unique.
*/
isUnique = 1;
/*
For each word through the string we use a for loop when the counter i
is below the index and while the isUnique value is 1.
*/
for (i = 0; i < index && isUnique; i++)
{
/*
Using the strcmp function we are able to check if the word in
question is in the uniqueWords array. If it is found we then
change the isUnique value to 0 to show that the value is not
unique and prevent the loop happening again.
*/
if (strcmp(uniqueWords[i], word) == 0)
isUnique = 0;
}
/* If word is unique then add it to the uniqueWords list
and increment index. Otherwise increment occurrence
count of current word.
*/
if (isUnique)
{
strcpy(uniqueWords[index], word);
count[index]++;
index++;
}
else
{
count[i - 1]++;
}
}
/*
For each item in the uniqueWords list we iterate through the words
and print them out in the correct format with the word and the following count of them.
*/
for (i = 0; i < index; i++)
{
printf("%s => %d\n", uniqueWords[i], count[i]);
}
}
I don't know if you are facing some requirements, but for all it's limitations in terms of standard library functions, C does have one that would make your job much easier, strstr, e.g.:
Live demo
#include <stdio.h>
#include <string.h>
int main() {
const char str[] = "stringstringdstringdstringadasstringipoistring";
const char* substr = "string";
const char* orig = str;
const char* temp = substr;
int length = 0;
while(*temp++){length++;} // length of substr
int count = 0;
char *ret = strstr(orig, substr);
while (ret != NULL){
count++;
//check next occurence
ret = strstr(ret + length, substr);
}
printf("%d", count);
}
The output should be 6.
Regarding user3121023's comment, scanf("%999[^\n]", word); parses all characters until it finds a \n or it reaches the width limit, and I agree fgets ( word, sizeof word, stdin); is better.

Reversing the order of words backwards in a string

Sorry for such a mediocre question, but I ran into what seems to be a tiny problem, but simply can't get over it. For my task I have to take a line of string from a file, and put it into another file backwards, for example:
one two three
four five six
would be
three two one
six five four
My problem is, is that I'm getting
three two one
si five four
So basically the flaw is that there is a space character at the beginning of each line and the last letter of the last word is always missing. Here's my reverse function:
void reverse(char input[], int length, char output[]) {
char space = 32;
input[length - 1] = space;
int value = 0;
int i, k = 0, j;
for (i = 0; i <= length; i++) {
if (input[i] == space) {
for (j = i - 1; j >= k; j--, value++) {
output[value] = input[j];
}
if (j == -1) {
output[value] = space;
value++;
}
k = i;
}
}
char c = 0;
for (int i = 0, j = length - 1; i <= j; i++, j--) {
c = output[i];
output[i] = output[j];
output[j] = c;
}
}
What I'm doing is first reversing each word by character, and then the whole line. If someone could help me find the last bits that I've missed I would greatly appreciate it.
The flaws come from your approach:
why do you force a space at offset length - 1? If you read the line with fgets(), there is probably a newline ('\n') at the end of the line, but it might be missing at the end of the input, which would explain the x getting overwritten on the last line.
you should not modify the input buffer.
Here is a simplified version, along with a simple main function:
#include <stdio.h>
#include <string.h>
void reverse(const char *input, int length, char *output) {
int i, j, k, v;
for (i = k = v = 0;; i++) {
if (i == length || input[i] == ' ') {
for (j = i; j-- > k; v++) {
output[v] = input[j];
}
for (; i < length && input[i] == ' '; i++) {
output[v++] = ' ';
}
if (i == length) {
output[v] = '\0';
break;
}
k = i;
}
}
for (i = 0, j = length - 1; i < j; i++, j--) {
char c = output[i];
output[i] = output[j];
output[j] = c;
}
}
int main() {
char input[256];
char output[256];
while (fgets(input, sizeof input, stdin)) {
reverse(input, strcspn(input, "\n"), output);
puts(output);
}
return 0;
}
Output:
three two one
six five four
Here is a simpler reverse function that operates in one pass:
#include <string.h>
void reverse(const char *input, int length, char *output) {
int i, j, k, v;
for (i = k = 0, v = length;; i++) {
if (i == length || input[i] == ' ') {
for (j = i; j-- > k;) {
output[--v] = input[j];
for (; i < length && input[i] == ' '; i++) {
output[--v] = ' ';
}
if (v == 0) {
output[length] = '\0';
break;
}
k = i;
}
}
}
Replace input[length - 1] = space; with input[length] = space;

Remove all '\' from a string in C

I am trying to get rid of all \ characters in a string in C. For example, if a string is co\din\g it should convert the string to coding.
So far I have the code
for(i = 0; i < strlen(string); ++i){
if(string[i] == '\'){
}
}
That looks to see if there is a backslash. I don't know how I would do to remove the backslash, however. My only idea is to set the next character equal to the current character, however, I don't know how changing the length of the string would work with memory.
like this:
#include <stdio.h>
int main(){
char st[] = "co\\din\\g";
int k = 0;
for (int i = 0; st[i] != '\0'; ++i)
if (st[i] != '\\')
st[k++] = st[i];
st[k] = '\0';
fputs(st, stdout);
return 0;
}
This works. Since you're only deleting characters, you can write back into the same string. At the end, the termination '\0' will move to a lower index, and the rest of the array will simply be ignored by printf. Also, \ is the escape character, so to pass the \ itself you must write \\.
#include <stdio.h>
void nukechar(char s[], char c)
{
size_t j = 0;
for (size_t i = 0; s[i] != '\0'; ++i) {
if (s[i] != c) {
s[j] = s[i];
++j;
}
}
s[j] = '\0';
}
int main(void)
{
char s[200];
while (fgets(s, 200, stdin) != NULL) {
nukechar(s,'\\');
printf("%s", s);
}
return 0;
}
The simplest solution would be to use a second string for the result:
#include <stdio.h>
#include <string.h>
int main(void)
{
char result[100] = {'\0'}, string[] = "co\\din\\g";
for(int i = 0, j = 0; i < strlen(string); i++)
{
if(string[i] != '\\')
result[j++] = string[i];
}
printf("%s %s\n", result, string);
return 0;
}
Result
$ gcc main.c -o main.exe; ./main.exe;
coding co\din\g
Note
It is necessary to use double backslashes, \\, so the character following the backslash is not interpreted as an escape sequence.

I am trying to compare string literals and I want to remove repeated literals I want to do it without using POINTERS.,

I am trying to compare string literals and I want to remove repeated literals I want to do it without using POINTERS.
This is my code:
char str[30];
printf("Enter strings : ");
fgets(str,29,stdin);
char tem[30];
int count , county;
for(count = 0 ; count < strlen(str)-1 ; count++) {
for(county = 1 ; county < strlen(str) ; county++) {
if(str[count] != str[county]) {
tem[count] = str[count];
}
}
}
//PRINT
for(count = 0 ;count < strlen(str) -1 ; count++) {
printf("%c",tem[count]);
}
Input: happen
Expected output: hapen
Correcting your code:
#include <stdio.h>
#include <string.h>
int main()
{
char str[30];
printf("Enter strings : ");
fgets(str,30,stdin);
char tem[30];
size_t count;
size_t county=0;;
for(count = 0 ; count < strlen(str)-1 ; count++) {
if(str[count] != str[count+1]) {
tem[county++] = str[count];
}
}
tem[county] = '\0';
printf("%s\n", tem);
return 0;
}
Take note that this code remove double chars if this char have +1 displacement in the sting.
EDIT
To have mspi as output of entered string mississippi
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main()
{
char str[30];
printf("Enter strings : ");
fgets(str,30,stdin);
char tem[30];
size_t count;
size_t county;
size_t tem_index = 0;
size_t size_of_string = strlen(str);
bool found;
for(count = 0 ; count < size_of_string-1; count++)
{
found = false;
county = count+1;
while ((found == false) && (county<size_of_string))
{
if(str[count] == str[county])
{
found = true;
}
county++;
}
if (found == false)
{
tem[tem_index++] = str[count];
}
}
tem[tem_index] = '\0';
printf("%s\n", tem);
return 0;
}
EDIT 2
To have misp as output of entered string mississippi
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main()
{
char str[30];
printf("Enter strings : ");
fgets(str,30,stdin);
char tem[30];
size_t count;
size_t county;
size_t tem_index = 0;
size_t size_of_string = strlen(str);
bool found;
for(count = 0 ; count < size_of_string-1; count++)
{
found = false;
county = 0;
while ((found == false) && (county<tem_index))
{
if(str[count] == tem[county])
{
found = true;
}
county++;
}
if (found == false)
{
tem[tem_index++] = str[count];
}
}
tem[tem_index] = '\0';
printf("%s\n", tem);
return 0;
}
Take note that all these solutions are case sensitive.
Your code to remove allduplicates isn't quite there yet:
You use the same indices for the new and the old string, but you need two different indices, because the new string is as long or shorter than the old string. If the old string is "aaab", your index for the old string is 3 when you see the "b", but the index for the new string is only 1. (By skipping indices you leave uninitialised gaps in your string.)
You look forward to find other occurrences of the same letter, but you append to the new string for every letter that doesn't atch. You must look at all folllowing letters, but you must append to the new string only once. That is, you must make your decision whether the letter is duplicate or not after the loop, based on the information that you've found in the loop.
When you look forward, you shouldn't start a 1, but at the letter after he current letter. If you start at one, you will find duplicates for every letter after the first, because you check each letter with itself.
This is not an arror, but it's not a good idea to call strlen repeatedly in a loop. The length of the input string doesn't change, so you can determine the string length beforehand. If you just want to use it as your termination condition, you can test whethet the current letter is the null terminator.
Below is a solution that uses your logic, albeit by looking backwards, not forward. (If you look forward, you will copy the last occurence of a letter, if you look back, you'll copy the first occurrence. It may make a difference in the order of the letters. For Mississippi, you'll get "Mspi" or "Misp" depending on which strategy you use.)
The program overwrites the same string. This is possible, because you are filtering out letters and the new index is equal to the old index or smaller:
#include <stdlib.h>
#include <stdio.h>
void remdup(char *str)
{
int i = 0; // index into old string
int j = 0; // index into new string
for (i = 0; str[i]; i++) {
int k = 0;
int dup = 0;
for (k = 0; k < i; k++) {
if (str[i] == str[k]) {
dup = 1;
break;
}
}
if (dup == 0) str[j++] = str[i];
}
str[j] = '\0';
}
int main()
{
char str[] = "Mississippi";
puts(str);
remdup(str);
puts(str);
return 0;
}
This solution doesn't scale for large strings. A more effective method would be to keep a table of which of the 256 possible characters have already been used.

Pattern matching in long text string

I wrote this code and it works in some cases. Sometimes, however, it fails, and I just can't see why. Can someone please help me spot the error?
It works for:
String: ishanthakkar ishan
patter: ishan
But it fails for:
String: cpr ograming
patter: cpr
Source:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *compute_prefix_function(char *pattern, int psize)
{
int k = -1;
int i = 1;
int *pi = malloc(sizeof(int)*psize);
if (!pi)
return NULL;
pi[0] = k;
for (i = 1; i < psize; i++) {
while (k > -1 && pattern[k+1] != pattern[i])
k = pi[k];
if (pattern[i] == pattern[k+1])
k++;
pi[i] = k;
}
return pi;
}
// This function find matching string in O(n) time, so iterate through text string only once, when unmatching character found; it proceed with next character and start comparing with first character of string to be searched i.e pattern
int kmp(char *target, int tsize, char *pattern, int psize)
{
int i;
int *pi = compute_prefix_function(pattern, psize);
int k = -1;
if (!pi)
return -1;
for (i = 0; i < tsize; i++) {
while (k > -1 && pattern[k+1] != target[i])
k = pi[k];
if (target[i] == pattern[k+1])
k++;
if (k == psize - 1) {
free(pi);
return i-k;
}
}
free(pi);
return -1;
}
int main(int argc, const char *argv[])
{
char target[200];
char *ch = target;
char pattern[20];
int i;
printf("Enter the string: \n");
fgets(target,100,stdin);
printf("Enter the string to be matched: \n");
fgets(pattern,20,stdin);
i = kmp(target, strlen(target), pattern, strlen(pattern));
if (i >= 0)
printf("matched #: %s\n", ch + i);
getch();
return 0;
}
The fgets function reads and includes the ending CR (or CRLF) in the string.
Add a chomp() function, like
void chomp(char *s) {
int n = strlen(s);
while (n && (s[n-1]==10 || s[n-1]==13)) s[--n] = 0;
}
that removes any CR or LF at the end of the string.
Then chomp() pattern and target before calling kmp() (and after the scanf())
chomp(target);
chomp(pattern);
i = kmp(target, strlen(target), pattern, strlen(pattern));
the program should behave better.
Note: 10 is '\n' (LF) and 13 is '\r' (CR)
Got clue:
i = kmp(target, strlen(target), pattern, strlen(pattern));
was passing string length+1(for null character) so it was giving false result for some text string
i = kmp(target, strlen(target)-1, pattern, strlen(pattern)-1);
works for all cases!
Thanks to all of you for your time!

Resources