what's wrong with my function (removing string from text file) - c

I want to write a function which removes certain word from text file. Program works fine but valgrind says something different:
==3411== Source and destination overlap in strcpy(0x51f1c90, 0x51f1c92)
==3411== at 0x4C2C085: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3411== by 0x400AD7: DELTEword (remove2.c:113)
==3411== by 0x4009A1: main (remove2.c:73)
also when I am trying to remove for instance word: "go" sometimes it happens that word "ro" is also removed. Why?
Here's my code:
int DELTEword(char *word, char *KEYword)
{
int i, k = 0, l = 0, length;
char *ptr;
if(word != NULL)
{
length = strlen(KEYword);
for(i = 0; word[i] != '\0'; i++)
{
if(word[i] == KEYword[k])
{
l++;
k++;
}
if(l == length)
{
ptr = &word[i];
strcpy((ptr - length) + 1, ptr + 1);
l = 0;
k = 0;
}
}
return 1;
}
else return 0;
}

Use memmove instead of strcpy to shuffle the data around, as strcpy is not recommended if source and destination is overlapping. memmove is safe to use in overlapping situations..

I think the problem is with the following piece of code
for(i = 0; word[i] != '\0'; i++)
{
if(word[i] == KEYword[k])
{
l++;
k++;
}
}
It does not look for continuous letters. If the letters do not match, then it would continue from the next. I mean the else part handling is missing.
May be this helps. This matches all occurences, I mean the word go in good. Can be tuned to your need.
length = strlen(KEYword);
for(i = 0; word[i] != '\0'; i++)
{
k = i;
l = 0;
for (j = 0; j < length; j++) {
if(word[k] == KEYword[j])
{
l++;
k++;
}
else
{
break;
}
}
/* All letters matched */
if (l == length) {
/* do some stuff */
}
}

Related

How to remove all repeated character in character array

I want to remove all the repeated characters from array. here is example.
"aabccdee"
"bd"
I'm doing this C language. use only array, loop, if,else(conditional statements) not using pointer.
#include<stdio.h>
int main() {
char c[10];
char com[10] = {0,};
char result[10] = { 0, };
int cnt = 0;
for (int i = 0; i < 10; i++) {
scanf("%c", &c[i]);
}
for (int i = 0; i < 10; i++) {
for (int j = i+1; j < 10; j++) {
if (c[i] == c[j]) {
com[i] = c[i];
cnt++;
printf("%c", com[i]);
}
}
}
for (int i = 0; i < cnt; i++) {
for (int j = 0; j < 10; j++) {
if (com[i] != c[j]) {
result[j] = c[j];
}
}
}
printf("\n");
for (int i = 0; i < 10; i++) {
printf("%c", result[i]);
}
}
I thought this
Make repeated array
Compare original array to repeated array
Output
But repeated array loop can't looping all original array.
How can I do remove all repeated character?
Not good SO policy to blatantly answer homework, but I rarely do it and thought this was an interesting task. Certainly making no claims on efficiency, but it looks like it works to me. As far as I can tell, the first and last cases are corner cases, so I handle those individually, and use a loop for everything in the middle. If you're not allowed to use strlen, then you can roll your own or use some other method, that's not the primary focus of this problem (would be best to fgets the string from a command line argument).
#include <stdio.h>
#include <string.h>
int main(void)
{
char source[] = "aabccdee";
char result[sizeof(source)] = { 0 };
unsigned resultIndex = 0;
unsigned i = 0;
// do this to avoid accessing out of bounds of source.
if (strlen(source) > 1)
{
// handle the first case, compare index 0 to index 1. If they're unequal, save
// index 0.
if (source[i] != source[i+1])
{
result[resultIndex++] = source[i];
}
// source[0] has already been checked, increment i to 1.
i++;
// comparing to strlen(source) - 1 because in this loop we are comparing the
// previous and next characters to the current. Looping from 1 to second-to-the-
// last char means we stay in bounds of source
for ( ; i < strlen(source) - 1; i++)
{
if (source[i-1] != source[i] && source[i] != source[i+1])
{
// write to result if curr char != prev char AND curr char != next char
result[resultIndex++] = source[i];
}
}
// handle the end. At this point, i == the last index of the string. Compare to
// previous character. If they're not equal, save the last character.
//
if (source[i] != source[i-1])
{
result[resultIndex] = source[i];
}
}
else if (strlen(source) == 1)
{
// if source is only 1 character, then it's trivial
result[resultIndex] = source[i];
}
else
{
// source has no length
fprintf(stderr, "source has no length.\n");
return -1;
}
// print source and result
printf("source = %s\n", source);
printf("result = %s\n", result);
return 0;
}
Various outputs for source:
source = "aabccdee"
result = "bd"
source = "aaee"
result =
source = "a"
result = "a"
source = "abcde"
result = "abcde"
source = "abcdee"
result = "abcd"
source = "aabcde"
result = "bcde"
source = "aaaaaaaaaaaabdeeeeeeee"
result = "bd"
source = ""
source has no length.
first of all before we speak , you have to check this
you need to put a whitespace when scaning a char using scanf
so
scanf("%c", &c[i]);
becomes
scanf(" %c", &c[i]);
secondly your idea is kinda a messy as the result showed you're only handling cases and it doesn't continue verifying the whole array . you need to learn how to shift an array to the right or left
your issue later on that when you shift your table(not completely) you still print out of the size .
so bascilly in general your code should be something like this :
#include<stdio.h>
int main() {
char c[10];
int length=5;
for (int i = 0; i < 5; i++) {
scanf(" %c", &c[i]);
}
int j,k,i;
for(i=0; i<length; i++)
{
for(j=i+1; j<length; j++)
{
if(c[i] == c[j])
{
length--;
for(k=j; k<length; k++)
{
c[k] = c[k + 1];
}
j--;
}
}
}
printf("\n");
for (int i = 0; i < length; i++) {
printf("%c", c[i]);
}
}
you simply take one case and compare it to the rest , if it exists you shift from the position you find for the second time the element and so on

In C , what can I use instead of strlen if I don't want to use a string function?

I recently started learning basic C and I am still noobie with it, I started doing some projects for learning and I am using library functions but I am interested in other methods...
So I have an email validation, it works fine, but I want to do it without strlen, any suggestion what can I do instead of strlen?
void mail(char e[]) {
int count = 0;
int countb = 0;
int i, j;
int t, t2;
int p = 0;
for (i = 0; i < strlen(e); i++) {
if (e[i] == '#') {
count++;
t = i;
}
}
if (count == 1) {
for (j = 0; j < t; j++) {
if (!(e[j] == '_' || e[j] == '.' || isalpha(e[j]) || isdigit(e[j]))) {
p = -1;
printf("\nwrong\n");
break;
}
}
if (p == 0) {
for (i = t; i < strlen(e); i++) {
if (e[i] == '.') {
t2 = i;
countb++;
}
}
if (countb == 1) {
for (i = 0; i < t2 && i > t2; i++) {
if (!(isalpha(e[i]))) {
p = -1;
printf("\nwrong\n");
break;
} else {
p = 1;
}
}
if (p == 1) {
if (e[t2 + 3] != '\0') {
p = -1;
printf("\nwrong\n");
}
}
} else {
p =- 1;
printf("\nwrong\n");
}
}
} else {
p = -1;
printf("\nwrong\n");
}
return;
}
Instead of comparing i < strlen(e) you can test if the byte at offset i is not the null terminator: e[i] != '\0'.
You can also compute the length of the string just once at the beginning of the function and store it into a len variable.
The only thing you can do is to implement your own strlen function.
In C, strings are null-terminated char arrays, that means, the last character of an array is '\0' (zero). The strlen function iterates over the character array until a null-character is found, it returns the length of that array, the null-character not included.
To duplicate (create) a c-string, you have to do the following:
char *str = malloc(strlen(another_string) + 1);
str[strlen(another_string)] = '\0';
Example for strlen:
size_t my_strlen(const char *str)
{
if (!str) return 0;
size_t n = 0;
for (; *str; ++n, ++str);
return n;
}
You can create you own my_strlen :)
unsigned int my_strlen(char *str)
OR
you can loop while your char is different of '\0' (null byte). So just replace strlen(e) with e[i] != '\0'
It should work just fine

Sorting words out in a string array

My program is designed to allow the user to input a string and my program will output the number of occurrences of each letters and words. My program also sorts the words alphabetically.
My issue is: I output the words seen (first unsorted) and their occurrences as a table, and in my table I don't want duplicates. SOLVED
For example, if the word "to" was seen twice I just want the word "to" to appear only once in my table outputting the number of occurrences.
How can I fix this? Also, why is it that i can't simply set string[i] == delim to apply to every delimiter rather than having to assign it manually for each delimiter?
Edit: Fixed my output error. But how can I set a condition for string[i] to equal any of the delimiters in my code rather than just work for the space bar? For example on my output, if i enter "you, you" it will out put "you, you" rather than just "you". How can I write it so it removes the comma and compares "you, you" to be as one word.
Any help is appreciated. My code is below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const char delim[] = ", . - !*()&^%$##<> ? []{}\\ / \"";
#define SIZE 1000
void occurrences(char s[], int count[]);
void lower(char s[]);
int main()
{
char string[SIZE], words[SIZE][SIZE], temp[SIZE];
int i = 0, j = 0, k = 0, n = 0, count;
int c = 0, cnt[26] = { 0 };
printf("Enter your input string:");
fgets(string, 256, stdin);
string[strlen(string) - 1] = '\0';
lower(string);
occurrences(string, cnt);
printf("Number of occurrences of each letter in the text: \n");
for (c = 0; c < 26; c++){
if (cnt[c] != 0){
printf("%c \t %d\n", c + 'a', cnt[c]);
}
}
/*extracting each and every string and copying to a different place */
while (string[i] != '\0')
{
if (string[i] == ' ')
{
words[j][k] = '\0';
k = 0;
j++;
}
else
{
words[j][k++] = string[i];
}
i++;
}
words[j][k] = '\0';
n = j;
printf("Unsorted Frequency:\n");
for (i = 0; i < n; i++)
{
strcpy(temp, words[i]);
for (j = i + 1; j <= n; j++)
{
if (strcmp(words[i], words[j]) == 0)
{
for (a = j; a <= n; a++)
strcpy(words[a], words[a + 1]);
n--;
}
} //inner for
}
i = 0;
/* find the frequency of each word */
while (i <= n) {
count = 1;
if (i != n) {
for (j = i + 1; j <= n; j++) {
if (strcmp(words[i], words[j]) == 0) {
count++;
}
}
}
/* count - indicates the frequecy of word[i] */
printf("%s\t%d\n", words[i], count);
/* skipping to the next word to process */
i = i + count;
}
printf("ALphabetical Order:\n");
for (i = 0; i < n; i++)
{
strcpy(temp, words[i]);
for (j = i + 1; j <= n; j++)
{
if (strcmp(words[i], words[j]) > 0)
{
strcpy(temp, words[j]);
strcpy(words[j], words[i]);
strcpy(words[i], temp);
}
}
}
i = 0;
while (i <= n) {
count = 1;
if (i != n) {
for (j = i + 1; j <= n; j++) {
if (strcmp(words[i], words[j]) == 0) {
count++;
}
}
}
printf("%s\n", words[i]);
i = i + count;
}
return 0;
}
void occurrences(char s[], int count[]){
int i = 0;
while (s[i] != '\0'){
if (s[i] >= 'a' && s[i] <= 'z')
count[s[i] - 'a']++;
i++;
}
}
void lower(char s[]){
int i = 0;
while (s[i] != '\0'){
if (s[i] >= 'A' && s[i] <= 'Z'){
s[i] = (s[i] - 'A') + 'a';
}
i++;
}
}
I have the solution to your problem and its name is called Wall. No, not the type to bang your head against when you encounter a problem that you can't seem to solve but for the Warnings that you want your compiler to emit: ALL OF THEM.
If you compile C code with out using -Wall then you can commit all the errors that people tell you is why C is so dangerous. But once you enable Warnings the compiler will tell you about them.
I have 4 for your program:
for (c; c< 26; c++) { That first c doesn't do anything, this could be written for (; c < 26; c++) { or perhaps beter as for (c = 0; c <26; c++) {
words[i] == NULL "Statement with no effect". Well that probably isn't what you wanted to do. The compiler tells you that that line doesn't do anything.
"Unused variable 'text'." That is pretty clear too: you have defined text as a variable but then never used it. Perhaps you meant to or perhaps it was a variable you thought you needed. Either way it can go now.
"Control reaches end of non-void function". In C main is usually defined as int main, i.e. main returns an int. Standard practice is to return 0 if the program successfully completed and some other value on error. Adding return 0; at the end of main will work.
You can simplify your delimiters. Anything that is not a-z (after lower casing it), is a delimiter. You don't [need to] care which one it is. It's the end of a word. Rather than specify delimiters, specify chars that are word chars (e.g. if words were C symbols, the word chars would be: A-Z, a-z, 0-9, and _). But, it looks like you only want a-z.
Here are some [untested] examples:
void
scanline(char *buf)
{
int chr;
char *lhs;
char *rhs;
char tmp[5000];
lhs = tmp;
for (rhs = buf; *rhs != 0; ++rhs) {
chr = *rhs;
if ((chr >= 'A') && (chr <= 'Z'))
chr = (chr - 'A') + 'a';
if ((chr >= 'a') && (chr <= 'z')) {
*lhs++ = chr;
char_histogram[chr] += 1;
continue;
}
*lhs = 0;
if (lhs > tmp)
count_string(tmp);
lhs = tmp;
}
if (lhs > tmp) {
*lhs = 0;
count_string(tmp);
}
}
void
count_string(char *str)
{
int idx;
int match;
match = -1;
for (idx = 0; idx < word_count; ++idx) {
if (strcmp(words[idx],str) == 0) {
match = idx;
break;
}
}
if (match < 0) {
match = word_count++;
strcpy(words[match],str);
}
word_histogram[match] += 1;
}
Using separate arrays is ugly. Using a struct might be better:
#define STRMAX 100 // max string length
#define WORDMAX 1000 // max number of strings
struct word {
int word_hist; // histogram value
char word_string[STRMAX]; // string value
};
int word_count; // number of elements in wordlist
struct word wordlist[WORDMAX]; // list of known words

How do I allocate memory to my char pointer?

My assignment is to allow the user to enter any input and print the occurrences of letters and words, we also have to print out how many one letter, two, three, etc.. letter words are in the string. I have gotten the letter part of my code to work and have revised my word function several times, but still can't get the word finding function to even begin to work. The compiler says the char pointer word is undeclared when it clearly is. Do I have to allocate memory to it and the array of characters?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void findLetters(char *ptr);
void findWords(char *point);
int main()
{
char textStream[100]; //up to 98 characters and '\n\ and '\0'
printf("enter some text\n");
if (fgets(textStream, sizeof (textStream), stdin)) //input up to 99 characters
{
findLetters(textStream);
findWords(textStream);
}
else
{
printf("fgets failed\n");
}
return 0;
}
void findLetters(char *ptr) //find occurences of all letters
{
int upLetters[26];
int loLetters[26];
int i;
int index;
for (i = 0; i < 26; i++) // set array to all zero
{
upLetters[i] = 0;
loLetters[i] = 0;
}
i = 0;
while (ptr[i] != '\0') // loop until prt[i] is '\0'
{
if (ptr[i] >= 'A' && ptr[i] <= 'Z') //stores occurrences of uppercase letters
{
index = ptr[i] - 'A';// subtract 'A' to get index 0-25
upLetters[index]++;//add one
}
if (ptr[i] >= 'a' && ptr[i] <= 'z') //stores occurrences of lowercase letters
{
index = ptr[i] - 'a';//subtract 'a' to get index 0-25
loLetters[index]++;//add one
}
i++;//next character in ptr
}
printf("Number of Occurrences of Uppercase letters\n\n");
for (i = 0; i < 26; i++)//loop through 0 to 25
{
if (upLetters[i] > 0)
{
printf("%c : \t%d\n", (char)(i + 'A'), upLetters[i]);
// add 'A' to go from an index back to a character
}
}
printf("\n");
printf("Number of Occurrences of Lowercase letters\n\n");
for (i = 0; i < 26; i++)
{
if (loLetters[i] > 0)
{
printf("%c : \t%d\n", (char)(i + 'a'), loLetters[i]);
// add 'a' to go back from an index to a character
}
}
printf("\n");
}
void findWords(char *point)
{
int i = 0;
int k = 0;
int count = 0;
int j = 0;
int space = 0;
int c = 0;
char *word[50];
char word1[50][100];
char* delim = "{ } . , ( ) ";
for (i = 0; i< sizeof(point); i++) //counts # of spaces between words
{
if ((point[i] == ' ') || (point[i] == ',') || (point[i] == '.'))
{
space++;
}
}
char *words = strtok(point, delim);
for(;k <= space; k++)
{
word[k] = malloc((words+1) * sizeof(*words));
}
while (words != NULL)
{
printf("%s\n",words);
strcpy(words, word[j++]);
words = strtok(NULL, delim);
}
free(words);
}
This is because you are trying to multiply the pointer position+1 by the size of pointer. Change line 100 to:
word[k] = malloc(strlen(words)+1);
This will solve your compilation problem, but you still have other problems.
You've got a couple of problems in function findWords:
Here,
for (i = 0; i< sizeof(point); i++)
sizeof(point) is the same as sizeof(char*) as point in a char* in the function fincdWords. This is not what you want. Use
for (i = 0; i < strlen(point); i++)
instead. But this might be slow as strlen will be called in every iteration. So I suggest
int len = strlen(point);
for (i = 0; i < len; i++)
The same problem lies here too:
word[k] = malloc((words+1) * sizeof(*words));
It doesn't makes sense what you are trying with (words+1). I think you want
word[k] = malloc( strlen(words) + 1 ); //+1 for the NUL-terminator
You got the arguments all mixed up:
strcpy(words, word[j++]);
You actually wanted
strcpy(word[j++], words);
which copies the contents of words to word[j++].
Here:
free(words);
words was never allocated memory. Since you free a pointer that has not been returned by malloc/calloc/realloc, the code exhibits Undefined Behavior. So, remove that.
You allocated memory for each element of word. So free it using
for(k = 0; k <= space; k++)
{
free(word[k]);
}
Your calculation of the pointer position+1 is wrong. If you want the compilation problem will go away change line 100 to:
word[k] = malloc( 1 + strlen(words));

Segmentation fault in searching for substring in string

Im trying to write a method that checks a string to see if it contains a substring. So for example if the user input was "hello" and they were searching the string for "lo" the output would be "true", but if they were searching for "ol" the output would be "false". This is for a class (I'm not looking for someone to do it for me) so i am supposed to do it by hand and not use many built in functions. Right now my code compiles and then gives me a segmentation fault:11.
void subsetCheck(char *string, char *srch){
char str[100];
char search[100];
strcpy(str, string);
strcpy(search, srch);
int i = 0, j = 0, flag = 0;
while(i < strlen(str)){
if(strcmp(str[i],search[j]) == 0){
for(j; j < strlen(search); j++){
if(strcmp(str[i],str[j]) != 0){
j = 0;
break;
}
else{
flag = 1;
}
}
}
i++;
}
if(flag == 1){
printf("TRUE");
}
else{
printf("FALSE");
}
return;
}
I edited my code, which entailed some of the things mentioned in the comments as well as rearranging some for loops and added in comments to try and explain what I think I'm doing at each step.
void subsetCheck(char *string, char *srch){
char str[100];
char search[100];
strcpy(str, string);
strcpy(search, srch);
int i = 0, j = 0, flag = 0, k = 0;
while(i < strlen(str)){
for(j; j <= strlen(search);j++){ //for length of the substring during each i iteration
if(str[i] == search[j]){ //if position i matches first letter in substring go into for loop
for(k; k <= strlen(search);k++){ //create variable k to allow iteration through strin without messing up placement of i, incase entire substrin isnt there
k = i;
if(str[k] != search[j]){ //if string position k doesnt equal position j, reassign both variables and break out of the loop
j = 0;
k = i;
flag = 0;
break;
}
else{ //if it does than assign flag the value of 1 and iterate both variables
flag = 1;
j++;
k++;
}
}
}
}
i++;
}
if(flag == 1){
printf("TRUE");
}
else{
printf("FALSE");
}
return;
}
if(strcmp(str[i],search[j]) == 0){
str[i] and search[j] are already single characters. You should use comparison operators instead of strcmp() to compare between characters.

Resources