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!
Related
Given some number in a form of string, I want to extract every k-th number from it. Then I go through the remaining string and extract every k-th number again. The thing I get as a result should be the number formed by these extracted ones(in a proper order). Example: 123456789, k = 3 --> 369485271
My algorithm is as follows: While the lenght of the string allows extracting every k-th number, I go through the string and store every k-th element in another string. Then I delete the extracted elements from the original string by tracking the proper index of an element and proceed forvard while the lenght of my str is sufficient.
I can't figure out what's the problem with my code. And maybe my approach isn't that good and there are some better/simpler ways of diong this?
#include <stdio.h>
#include <string.h>
void remove(char *str, unsigned int index) {
char *src;
for (src = str+index; *src != '\0'; *src = *(src+1),++src) ;
*src = '\0';
}
int main() {
char number[100];
char result[100];
int k;
printf("Enter a string: ");
scanf("%s",number);
printf("Enter a key: ");
scanf("%d",&k);
while (strlen(number)>k-1) {
for (int i = 0, p = 0; number[i] != '\0'; i++) {
if (i % k == (k-1)) {
result[p] = number[i];
p++;
}
}
for (int j = 0; number[j] != '\0'; j++){
if (j % k == (k-1)) {
remove(number, j);
j+=1; /*since the index was shifted due to removing an element*/
}
}
}
puts(result);
return 0;
}
You some issues:
You start writing your output from scratch again in each iteration of your while loop.
You do not handle the last digits
You do not treat the input as a cyclic input.
You do not terminate your output string.
remove is already a name of standard library function.
A shorter version could be this (untested):
#include <stdio.h>
#include <string.h>
void remove_digit(char *str, unsigned int index) {
char *src;
for (src = str+index; *src != '\0'; *src = *(src+1),++src)
;
}
int main() {
char number[100];
char result[100];
int k;
printf("Enter a string: ");
scanf("%s",number);
printf("Enter a key: ");
scanf("%d",&k);
int p = 0;
int i = 0;
int skip = k-1; // We remove 1 digit and skip k-1 digits
while (number[0] != 0) {
i = (i + skip) % strlen(number);
result[p] = number[i];
p++;
remove_digit(number, i);
}
number[p] = 0;
puts(result);
return 0;
}
The following code seems to be what you want:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void remove_(char *str, unsigned int index) {
char *src;
for (src = str+index; *src != '\0'; *src = *(src+1),++src) ;
*src = '\0';
}
int main(int argc, const char * argv[]) {
char number[100];
char result[100];
int tmp[100];
int k;
printf("Enter a string: ");
scanf("%s",number);
printf("Enter a key: ");
scanf("%d",&k);
int p = 0;
for (int tp = 0; strlen(number) > k-1; tp = 0) {
for (int i = 0; number[i] != '\0'; i++)
if (i % k == (k-1))result[p++] = number[i];
for (int j = 0; number[j] != '\0'; j++)
if (j % k == (k-1)) tmp[tp++] = j;
for (; tp; --tp) remove_(number, tmp[tp-1]);
}
// The newly added code
for (int index; strlen(number); ) {
index = (k-1) % strlen(number);
result[p++] = number[index];
remove_(number, index);
}
puts(result);
return 0;
}
The most important thing is that every while loop, you need to remove the elements in number at once. While ensuring the integrity of your original code, I made some changes. Unfortunately, the main idea of the original code is wrong.
It should circulate from the tail (including the rest) to the head after one round. But I found that the function of the code you provided is that after each round, the next round starts from the 0th element of the head.
By the way, your algorithm is similar to the Josephus problem
I was doing the cs50 pset 2 - substitution, where we have to encrypt the plaintext using the key given by the user in the command line, but the following code isn't prompting for an input. What am I doing wrong? Any help would be greatly appreciated!
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
int check(int c, string key);
int main(int argc, string argv[])
{
int checkR = check(argc, argv[1]);
if(checkR == 1)
{
return 1;
}
else
{
string key = argv[1];
string ptext = get_string("plaintext: ");
int len = strlen(ptext);
char ctext[len];
for (int i = 0; i < len; i++)
{
if(isupper(ptext[i]))
ctext[i] = toupper(key[(int)ptext[i] - 65]);
else if(islower(ptext[i]))
ctext[i] = tolower(key[(int)ptext[i] - 97]);
else
ctext[i] = ptext[i];
}
printf("ciphertext: %s\n", ctext);
return 0;
}
}
int check(int c, string key)
{
int keyL = strlen(key);
if(c != 2)
return 1;
else if(keyL != 26)
return 1;
for(int i = 0; i < keyL - 1; i++)
{
for(int j = i; j < keyL; j++)
{
if(key[i] == key[j])
return 1;
}
}
return 0;
}
Answer for the question
In the check function, you initialized the inner loop as int j = i.
Therefore, in the first iteration, key[i] == key[j] will be always true.
Then, 1 is returned from check and it prevents main function from printing the prompt.
The initialization should be int j = i + 1.
Other mistakes
Firstly, it is bad to do int keyL = strlen(key); before checking c because key (argv[1]) may be NULL when c (argc) is less than 2.
Secondly, printf("ciphertext: %s\n", ctext); in this code will invoke undefined behavior because what is stored in ctext is not NUL-terminated.
char ctext[len]; should be char ctext[len+1]; and ctext[len]='\0'; should be added before printf("ciphertext: %s\n", ctext);.
So I have an assignment where I should delete a character if it has duplicates in a string. Right now it does that but also prints out trash values at the end. Im not sure why it does that, so any help would be nice.
Also im not sure how I should print out the length of the new string.
This is my main.c file:
#include <stdio.h>
#include <string.h>
#include "functions.h"
int main() {
char string[256];
int length;
printf("Enter char array size of string(counting with backslash 0): \n");
/*
Example: The word aabc will get a size of 5.
a = 0
a = 1
b = 2
c = 3
/0 = 4
Total 5 slots to allocate */
scanf("%d", &length);
printf("Enter string you wish to remove duplicates from: \n");
for (int i = 0; i < length; i++)
{
scanf("%c", &string[i]);
}
deleteDuplicates(string, length);
//String output after removing duplicates. Prints out trash values!
for (int i = 0; i < length; i++) {
printf("%c", string[i]);
}
//Length of new string. The length is also wrong!
printf("\tLength: %d\n", length);
printf("\n\n");
getchar();
return 0;
}
The output from the printf("%c", string[i]); prints out trash values at the end of the string which is not correct.
The deleteDuplicates function looks like this in the functions.c file:
void deleteDuplicates(char string[], int length)
{
for (int i = 0; i < length; i++)
{
for (int j = i + 1; j < length;)
{
if (string[j] == string[i])
{
for (int k = j; k < length; k++)
{
string[k] = string[k + 1];
}
length--;
}
else
{
j++;
}
}
}
}
There is a more efficent and secure way to do the exercise:
#include <stdio.h>
#include <string.h>
void deleteDuplicates(char string[], int *length)
{
int p = 1; //current
int f = 0; //flag found
for (int i = 1; i < *length; i++)
{
f = 0;
for (int j = 0; j < i; j++)
{
if (string[j] == string[i])
{
f = 1;
break;
}
}
if (!f)
string[p++] = string[i];
}
string[p] = '\0';
*length = p;
}
int main() {
char aux[100] = "asdñkzzcvjhasdkljjh";
int l = strlen(aux);
deleteDuplicates(aux, &l);
printf("result: %s -> %d", aux, l);
}
You can see the results here:
http://codepad.org/wECjIonL
Or even a more refined way can be found here:
http://codepad.org/BXksElIG
Functions in C are pass by value by default, not pass by reference. So your deleteDuplicates function is not modifying the length in your main function. If you modify your function to pass by reference, your length will be modified.
Here's an example using your code.
The function call would be:
deleteDuplicates(string, &length);
The function would be:
void deleteDuplicates(char string[], int *length)
{
for (int i = 0; i < *length; i++)
{
for (int j = i + 1; j < *length;)
{
if (string[j] == string[i])
{
for (int k = j; k < *length; k++)
{
string[k] = string[k + 1];
}
*length--;
}
else
{
j++;
}
}
}
}
You can achieve an O(n) solution by hashing the characters in an array.
However, the other answers posted will help you solve your current problem in your code. I decided to show you a more efficient way to do this.
You can create a hash array like this:
int hashing[256] = {0};
Which sets all the values to be 0 in the array. Then you can check if the slot has a 0, which means that the character has not been visited. Everytime 0 is found, add the character to the string, and mark that slot as 1. This guarantees that no duplicate characters can be added, as they are only added if a 0 is found.
This is a common algorithm that is used everywhere, and it will help make your code more efficient.
Also it is better to use fgets for reading input from user, instead of scanf().
Here is some modified code I wrote a while ago which shows this idea of hashing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NUMCHAR 256
char *remove_dups(char *string);
int main(void) {
char string[NUMCHAR], temp;
char *result;
size_t len, i;
int ch;
printf("Enter char array size of string(counting with backslash 0): \n");
if (scanf("%zu", &len) != 1) {
printf("invalid length entered\n");
exit(EXIT_FAILURE);
}
ch = getchar();
while (ch != '\n' && ch != EOF);
if (len >= NUMCHAR) {
printf("Length specified is longer than buffer size of %d\n", NUMCHAR);
exit(EXIT_FAILURE);
}
printf("Enter string you wish to remove duplicates from: \n");
for (i = 0; i < len; i++) {
if (scanf("%c", &temp) != 1) {
printf("invalid character entered\n");
exit(EXIT_FAILURE);
}
if (isspace(temp)) {
break;
}
string[i] = temp;
}
string[i] = '\0';
printf("Original string: %s Length: %zu\n", string, strlen(string));
result = remove_dups(string);
printf("Duplicates removed: %s Length: %zu\n", result, strlen(result));
return 0;
}
char *remove_dups(char *str) {
int hash[NUMCHAR] = {0};
size_t count = 0, i;
char temp;
for (i = 0; str[i]; i++) {
temp = str[i];
if (hash[(unsigned char)temp] == 0) {
hash[(unsigned char)temp] = 1;
str[count++] = str[i];
}
}
str[count] = '\0';
return str;
}
Example input:
Enter char array size of string(counting with backslash 0):
20
Enter string you wish to remove duplicates from:
hellotherefriend
Output:
Original string: hellotherefriend Length: 16
Duplicates removed: helotrfind Length: 10
I have made two functions that find a substring index and substitute that substring in the string. I'm glad I jury rigged this at all, given that similar questions previously asked were never answered/marked as closed without any help. Is there a cleaner method?
void destroy_substr(int index, int len)
{
int i;
for (i = index; i < len; i++)
{
string[i] = '~';
}
}
void find_substr_index(char* substr)
{
int i;
int j;
int k;
int count;
int len = strlen(substr);
for (i = 0; i < strlen(string); i++)
{
if (string[i] == substr[0])
{
for(j = i, k = 0; k < len; j++, k++)
{
if (string[j] == substr[k])
{
count++;
}
if (count == len)
destroy_substr((j - len + 1), len);
}
j = 0;
k = 0;
count = 0;
}
}
}
Your code seems like you're trying to re-inventing your own wheel.
By using standard C functions, which is strstr() and memset(), you can achieve the same result as you expected.
#include <stdio.h>
#include <string.h>
char string[] = "foobar foobar foobar";
char substr[] = "foo";
char replace = '~';
int main() {
int substr_size = strlen(substr);
// Make a copy of your `string` pointer.
// This is to ensure we can safely modify this pointer value, without 'touching' the original one.
char *ptr = string;
// while true (infinite loop)
while(1) {
// Find pointer to next substring
ptr = strstr(ptr, substr);
// If no substring found, then break from the loop
if(ptr == NULL) { break; }
// If found, then replace it with your character
memset(ptr, replace, substr_size);
// iIncrement our string pointer, pass replaced substring
ptr += substr_size;
}
printf("%s\n", string);
return 0;
}
How about this:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char string[] = "HELLO hello WORLD world HELLO hello ell";
char substring[] = "ell";
int stringLength = strlen(string);
int substringLength = strlen(substring);
printf("Before: %s\n", string);
if(substringLength <= stringLength)
{
int i;
int j;
for(i = 0, j = stringLength - substringLength + 1; i < j; )
{
if(memcmp(&string[i], substring, substringLength) == 0)
{
memset(&string[i], '~', substringLength);
i += substringLength;
}
else
{
i++;
}
}
}
printf("After: %s\n", string);
return 0;
}
Key ideas are:
You only need to scan the string (stringLength - substringLength) times
You can use functions from string.h to do the comparison and to replace the substring
You can copy the new string in place. If you want to support insertion of longer strings you will need to manage memory with malloc()/realloc(). If you want to support insertion of smaller strings you'll need to advance the pointer to the beginning by the length of the replacement string, copy the rest of the string to that new location, then zero the new end of the string.
#include <stdio.h>
#include <string.h>
#include <err.h>
int main(int argc, char **argv)
{
char *str = strdup("The fox jumps the dog\n");
char *search = "fox";
char *replace = "cat";
size_t replace_len = strlen(replace);
char *begin = strstr(str, search);
if (begin == NULL)
errx(1, "substring not found");
if (strlen(begin) < replace_len)
errx(1, "replacement too long");
printf("%s", str);
memcpy(begin, replace, replace_len);
printf("%s", str);
return 0;
}
how to parse a empty substring with sscanf.......
if my string str[]="is first,,third,final." i cannot able to read the third and final substring if my second substring is zero. Is there an solution to overcome this error.....?????
**Code:**
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
char *tokenstring = "first,second,25.5,15";
int result, i;
double fp;
char o[10], f[10], s[10], t[10];
void main()
{
result = sscanf(tokenstring,"%[^','],%[^','],%[^','],%s", o,t,s,f);`sscanf function`
fp = atof(s);
i = atoi(f);
printf("%s\n %lf\n %s\n %d\n", o,t,fp,i);
}
for this program if i execute my output is
`output`
>first
>second
>25.5
>15
but if i try to remove the substring "second" in the tokenstring pointer... and if i try to execute, then i get output as:
char *tokenstring = "first,,25.5,15";
>first
>(blank)
>0.00
>0
how do i read the third and fourth substring in the string"tokenstring"...any suggestions ?????????? .
Parse the input character-by-character
char part[4][1000] = {0};
const char *input = "first,,25.5,15";
size_t k, n;
for (k = 0; k < 4; k++) {
char *curr = part[k];
while (*input && *input != ',') {
*curr++ = *input++;
}
if (*input == ',') input++; else break;
}
/* (k+1) elements have been parsed */
for (n = 0; n < k + 1; n++) {
printf("part %d (between square parenthesis): [%s]\n", (int)n, part[n]);
}