I have a program that has to count the number of duplicate characters in a string. For example "aaabcc" should return "a3b1c2" and "aaabcccc..a" should return "a3b1c4.2a1". I am currently using sprintf to concatenate the string and numbers like this: sprintf(s, "%s%c%d", s, prev, count);, where s is the string containing the result. But that causes an error since I am using "s" as an input and also as the destination. Is there some way around this?
This is my code right now:
char *s = (char *)malloc(sizeof(char) * 100);
char prev = argv[1][0];
if(isdigit(prev)!=0){
printf("%s","ERROR");
return 0;
}
int count = 1;
for(int i=1; i<strlen(argv[1]); i++){
if(isdigit(argv[1][i])!=0){
printf("%s","ERROR");
return 0;
}
//check if same as previous letter
if(prev==argv[1][i]){
count++;
}else{
//add letter and count to string
//problem
sprintf(s, "%s%c%d", s, prev, count);
count = 1;
}
//update prev
prev=argv[1][i];
}
//add it to string
//problem
sprintf(s, "%s%c%d", s, prev, count);
//check if result is smaller than input
if(strlen(s) > strlen(argv[1])){
printf("%s\n", argv[1]);
}else{
printf("%s\n", s);
}
free(s);
Use a different buffer for sprintf(), then concatenate to s with strcat().
Make sure you initialize s to an empty string after allocating it.
Instead of allocating a hard-coded size for s, allocate a string big enough for the worst case (every character repeated just once, so it's a1b1c1...).
temp can be a short, fixed-size string, since it just has to hold the length of one run.
char *s = malloc(strlen(argv[1]) * 2 + 1);
s[0] = '\0';
char temp[20];
char prev = argv[1][0];
if(isdigit(prev)!=0){
printf("%s","ERROR");
return 0;
}
int count = 1;
for(int i=1; i<strlen(argv[1]); i++){
if(isdigit(argv[1][i])!=0){
printf("%s","ERROR");
return 0;
}
//check if same as previous letter
if(prev==argv[1][i]){
count++;
}else{
//add letter and count to string
sprintf(temp, "%c%d", prev, count);
strcat(s, temp);
count = 1;
}
//update prev
prev=argv[1][i];
}
//add it to string
sprintf(temp, "%s%c%d", prev, count);
strcat(s, temp);
//check if result is smaller than input
if(strlen(s) > strlen(argv[1])){
printf("%s\n", argv[1]);
}else{
printf("%s\n", s);
}
free(s);
The advice in the comments and other answers are giving you good guidance on how manage the strings that you are dynamically allocating with malloc. But you can simplify your entire program without ever allocating a string and without using sprintf.
Consider this:
int lastChar = '\0';
int count = 0;
const char* arg = argv[1];
int isError = 0;
if (argc < 2) {
isError = 1;
}
while (*arg & !isError) { // scan argv[1] for digits
isError = isdigit(*arg);
arg++;
}
arg = argv[1]; // reset arg back to beginning of argv[1]
while (*arg && !isError) {
if (lastChar == *arg) {
count++;
}
else {
if (count > 0) {
printf("%c%d", lastChar, count);
}
lastChar = *arg;
count = 1;
}
arg++;
}
// print the last character being tracked or error message
if (isError) {
printf("ERROR");
}
else if (count > 0) {
printf("%c%d", lastChar, count);
}
printf("\n");
Related
I am supposed to save every sequence of digits from a string in an array of chars , this is what i tried:
#include<stdio.h>
#include<ctype.h>
#include<string.h>
int check_number(char *s) {
for (; *s; ++s) {
if (!isdigit(*s))
return 0;
}
return 1;
}
void int_in_string(char *s, char **ar, int MaxCap) {
char temp[100];
int index = 0;
int i = 0;
for (; *s; s++) {
if (index == MaxCap) {
break;
}
if (isdigit(*s)) {
temp[i++] = *s;
}
if (*s == ' ' && check_number(temp)) {
ar[index++] = temp;
memset(temp, '\0', i);
i = 0;
}
}
if (index == 0) {
printf("no numbers in string");
}
for (int i = 0; i < index; i++)
printf(" %s \n", ar[i]);
}
but this code only prints several newlines , can someone explain me what i do wrong?
Some issues:
ar[index++]=temp;
This is just storing the same value (the address of temp) over and over. What you need to do is copy the string into the array.
Also, you need to terminate the string temp with '\0'. You handle this in all but the first string with memset(temp, '\0', i); However, since local variables are not initialized, you need to do it:
char temp[100] = {0}
Or, you can remove the initialization and the memset by just adding the EOS:
temp[i] = '\0';
Lastly, since you declare the original array as
char * ar[10];
You are not allocating any space for the strings. The simplest way to handle that is with strdup.
void int_in_string(char *s, char **ar, int MaxCap)
{
char temp[100];
int index = 0;
int i = 0;
for (; *s; s++) {
if (isdigit(*s)) {
temp[i++] = *s;
// Need to avoid buffer overflow
if (i == sizeof(temp)) {
i = 0;
}
}
if (isspace(*s)) {
temp[i] = '\0';
// strdup will allocate memory for the string, then copy it
ar[index++] = strdup(temp);
// if (NULL == ar[index-1]) TODO: Handle no memory error
i = 0;
if (index == MaxCap) {
break;
}
}
}
if (index == 0) {
printf("no numbers in string");
}
for (int i = 0; i < index; i++) {
printf(" %s \n", ar[i]);
// free the mem from strdup
free(ar[i]);
}
}
I believe some systems may not have strdup(). If not, it can be easily replicated:
char * my_strdup(const char *src)
{
if (src == NULL) return NULL;
char *dest = malloc(strlen(src) + 1);
if (dest == NULL) return NULL;
strcpy(dest, src);
return dest;
}
I need to find all occurrences and output all positions of a substring in a string.
For example: my string is abaaab, my substring is aa, position is 3 and 4, because in aaa my substr is repeated twice.
I want the position at the end to be printed from right to left, and after the position of substring I want the number of occurrences of my subtring.
I tried to do it and I have this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char *str, c;
int x = 0, y = 1;
str = (char*)malloc(sizeof(char));
printf("Inserisci stringa principale : ");
while (c != '\n') {
// read the input from keyboard standard input
c = getc(stdin);
// re-allocate (resize) memory for character read to be stored
str = (char*)realloc(str, y * sizeof(char));
// store read character by making pointer point to c
str[x] = c;
x++;
y++;
}
str[x] = '\0'; // at the end append null character to mark end of string
printf("\nLa stringa inserita : %s", str);
char *sub, b;
int w = 0, z = 1;
sub = (char*)malloc(sizeof(char));
printf("Immetti sottostringa da cercare : ");
while (b != '\n') {
// read the input from keyboard standard input
b = getc(stdin);
// re-allocate (resize) memory for character read to be stored
sub = (char*)realloc(sub, z * sizeof(char));
// store read character by making pointer point to c
sub[w] = b;
w++;
z++;
}
sub[w] = '\0'; // at the end append null character to mark end of string
char *p1, *p2, *p3;
int i=0,j=0,flag=0;
p1 = str;
p2 = sub;
for(i = 0; i<strlen(str); i++)
{
if(*p1 == *p2)
{
p3 = p1;
for(j = 0;j<strlen(sub);j++)
{
if(*p3 == *p2)
{
p3++;p2++;
}
else
break;
}
p2 = sub;
if(j == strlen(sub))
{
flag = 1;
printf("\nSottostringa trovata all'indice : %d\n",i);
}
}
p1++;
}
if(flag==0)
{
printf("Sottostringa non trovata");
}
free(str);
free(sub);
return (0);
}
But it only shows me the position of the first occurrence, and not the number of occurrences.
There are multiple problems in your code:
Your string reallocation scheme is incorrect: the space allocated is one byte too short for the string and you never test for memory allocation failure. You could use getline() if your system supports it or at least write a function to factorize the code.
c is unsinitialized the first time you loop test c != '\n': this has undefined behavior.
Your matching algorithm is too complicated: you use both index values and moving pointers. Use one or the other.
Here is a simplified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* read an allocated string from stream.
stop at newline, not included in string.
Return NULL upon EOF
*/
char *my_getline(FILE *stream) {
char *line = NULL;
size_t pos = 0;
int c;
while ((c = getc(stream)) != EOF) {
char *newp = realloc(line, pos + 2);
if (newp == NULL) {
free(line);
return NULL;
}
line = newp;
if (c == '\n')
break;
line[pos++] = (char)c;
}
if (line) {
line[pos] = '\0';
}
return line;
}
int main(void) {
char *str, *sub;
size_t len1, len2, i, count = 0;
// type the main string
printf("Inserisci stringa principale :\n");
str = my_getline(stdin);
// type the substring to search for
printf("Immetti sottostringa da cercare :\n");
sub = my_getline(stdin);
if (str && sub) {
len1 = strlen(str);
len2 = strlen(sub);
for (i = 0; i + len2 <= len1; i++) {
if (!memcmp(str + i, sub, len2)) {
count++;
// substring found at offset
printf("Sottostringa trovata all'indice : %zu\n", i);
}
}
if (count == 0) {
// substring not found
printf("Sottostringa non trovata\n");
}
}
free(str);
free(sub);
return 0;
}
Notes:
The above code finds matches for the empty substring at every offset in the search string. Whether matches should be found or not is a question of specification, but this behavior is consistent with that of strstr().
you could also use standard function strstr() to locate the matches.
Here is a version of the main loop using strstr():
if (str && sub) {
for (char *p = str; (p = strstr(p, sub)) != NULL; p++) {
count++;
// substring found at offset
printf("Sottostringa trovata all'indice : %tu\n", p - str);
if (*p == '\0') /* special case for the empty string */
break;
}
if (count == 0) {
// substring not found
printf("Sottostringa non trovata\n");
}
}
I've checked you code and it seems that your code has problem in the line
if(j == strlen(sub))
Since j is starting from 0 it will always be 1 less than the length of the sub string, change your code to
if(j+1 == strlen(sub))
and it should solve your problem.
For number of occurrences you need another variable to count whenever there is a match with the substring, modifying the if block
if(j+1 == strlen(sub))
{
flag = 1;
occurrences+=1; //declare variable occurrences and initialize it to 0
printf("\nSottostringa trovata all'indice : %d\n",i);
}
Then after the end of the loop just print the 'occurrences' to get the desired result.
Also this is not an efficient way to solve the problem, you can refer to
https://www.topcoder.com/community/data-science/data-science-tutorials/introduction-to-string-searching-algorithms/
for better approach.
A trivial way of finding each occurrence is a strstr called in a loop. After each match, let strstr search one position after that where the match has been found:
int main( ) {
const char *string = "abaaab";
const char *toSearch = "aa";
int nrOfOccurences = 0;
printf("searching for occurences of '%s' in string '%s':\n", string, toSearch);
const char* pos = string;
while (pos) {
pos = strstr(pos, toSearch);
if (pos) {
printf("found occurence at position %td\n", pos-string);
nrOfOccurences++;
pos++; // skip one character
}
}
nrOfOccurences = findRecursive(string, toSearch, 0,0);
printf("nr of occurences: %d\n", nrOfOccurences);
return 0;
}
If you need - as somehow stated - to print the occurrences starting from the last one, you could use a recursive function like the following. A comment in the code above shows how to use it:
int findRecursive(const char* str, const char* toSearch, ptrdiff_t pos, int nrOfOccurences) {
char *next = strstr(str, toSearch);
if (next) {
ptrdiff_t foundPos = pos + next - str;
nrOfOccurences = findRecursive(next+1, toSearch, foundPos+1, nrOfOccurences+1);
printf("occurence found at position %td\n", foundPos);
}
return nrOfOccurences;
}
I have a dictionary of words stored in a 2D char array. I also have a scanned word stored in a structure. I'm trying to 'thin down' my main dictionary by copying words of length equal to the scanned word into a seperate 2D array. Then I want to print the new array out.
i.e if scanned word = hello, all words of the same length will be copied into the new array.
My code just prints the first word of the array infinitely
words.startword is the scanned word.
void get_equal_length (char equal_length_dictionary[MAX_WORDS][MAX_WORD_LENGTH], char dictionary[MAX_WORDS][MAX_WORD_LENGTH], Scanned_words words)
{
int i, word_count = 0;
for (i = 0; dictionary[i] != '\0'; i++)
{
if (strlen(*dictionary) == strlen(words.startword))
{
strcpy(*equal_length_dictionary, *dictionary);
word_count++;
printf("Word #%d: %s\n", word_count, *equal_length_dictionary);
}
}
printf("Equal length words: %d\n", word_count);
}
for (i = 0; dictionary[i] != '\0'; i++)
{
if (strlen(dictionary) == strlen(words.startword))
{
strcpy(*equal_length_dictionary, *dictionary);
should be:
for (i = 0; dictionary[i][0] != '\0'; i++)
{
if (strlen(dictionary[i]) == strlen(words.startword))
{
strcpy(equal_length_dictionary[i], dictionary[i]);
Also, to improve speed, better calculate strlen(words.startword) only once before the loop, instead of recalculating it inside the loop at each iteration. You should also not forget to terminate the new array with a null string.
The full code will be:
void get_equal_length(char equal_length_dictionary[MAX_WORDS][MAX_WORD_LENGTH], char dictionary[MAX_WORDS][MAX_WORD_LENGTH], Scanned_words words)
{
int i, word_count = 0, len = strlen(words.startword);
for (i = 0; dictionary[i][0] != '\0'; i++)
{
if (strlen(dictionary[i]) == len)
{
strcpy(equal_length_dictionary[i], dictionary[i]);
word_count++;
printf("Word #%d: %s\n", word_count, equal_length_dictionary[i]);
}
}
// now we will also terminate the new array with a null string
equal_length_dictionary[i][0] = '\0';
printf("Equal length words: %d\n", word_count);
}
This should work, although not tested. As Kevin mentioned in the comment, you need to use the index i in the loop. You also should use word_count as index:
void get_equal_length (char equal_length_dictionary[MAX_WORDS][MAX_WORD_LENGTH], char dictionary[MAX_WORDS][MAX_WORD_LENGTH], Scanned_words words)
{
int i, word_count = 0;
for (i = 0; i < MAX_WORDS; i++)
{
char* cur_word = dictionary[i];
if (!cur_word || !*cur_word)
break;
if (strlen(cur_word) == strlen(words.startword))
{
strcpy(equal_length_dictionary[word_count], cur_word);
word_count++;
printf("Word #%d: %s\n", word_count, equal_length_dictionary[word_count]);
}
}
printf("Equal length words: %d\n", word_count);
}
I am writing a code to rearrange the words in a string from back to front. I have first managed to arranged the characters from back to front but cannot seem to reset a string to null before swapping the second word in the string a second time and so on.
For example, with the input, "What the hell is going on here"
The output turns out to be, "here onre going ising hellg thelg Whatg"
So the last letters of the previous word stay with the "tempWord" variable. How can I fix this?
void revString(char statement[]);
int main (void){
int index;
char tempWord[LENGTH];
char statement[LENGTH] = "What the hell is going on here";
const char s[2] = " ";
char *word;
int wordCounter = 0;
revString(statement);
printf("%s\n", statement); //Temp printing
(Just so it's clear, the code I'm asking about is below this line)
//////////////////////////////////////////////////////////////////////////////////////
index = 0;
word = strtok(statement, s);
while (word != NULL){
wordCounter++;
for (index = 0; index <= strlen(word); index++){
tempWord[index] = '\0';
}
strcpy(tempWord, word);
revString(tempWord);
printf("%s ", tempWord);
word = strtok(NULL, s);
}
printf("\n");
printf("%d words", wordCounter);
}
Let me know what you think!
void revString(char original[]){
int index;
char temp[LENGTH];
int j = 1;
for (index = 0; index < strlen(original); index++, j++){
temp[(strlen(original) - j)] = original[index];
}
strcpy(original, temp);
original[strlen(original)] = '\0';
}
The problem is temp is not terminated with '\0'.
I modified the revString and tweaked a bit (called strlen only once)...
void revString(char original[]){
int index;
char temp[LENGTH];
int j = 1;
int len = strlen(original);
temp[len] = '\0';
for (index = 0; index < len; index++, j++){
temp[len - j] = original[index];
}
strcpy(original, temp);
original[len] = '\0';
}
Interestingly your original code doesn't give me a problem for LENGTH values from 30 to 100. For more than 200 bytes values it gives me strange characters (possibly the garbage) which got me into setting the last character in string "temp" to NULL.
Set the terminating Null character for tempword, according to the length of word
i.e.
while (word != NULL){
wordCounter++;
strcpy(tempWord, word);
revString(tempWord);
tempWord[strlen(word)] = '\0';
printf("%s ", tempWord);
word = strtok(NULL, s);
}
printf("\n");
printf("%d words", wordCounter);
}
I have an array of string from which i have to find duplicate string and then remove that duplicate string like i have string
char aa[50]="Amit Hanish Mahesh Amit"
Now Amit is duplicate and have to remove it from string .
#include "string.h"
main()
{
char x[100] = "Amit Hanish Mahesh Amit";
char y[3][100];
int i = 0, k = 0, j = 0, c = 0, end, t;
int current = 1;
while (x[i] != '\0') {
if (x[i] != ' ') {
y[k][j] = x[i];
j++;
i++;
} else {
// c = c + 1;
i++;
k++;
j = 0;
}
y[k][j] = '\0';
}
for (end = 1; end <= 3; end++) {
for (t = 0; t < end; t++) {
if (strcmp(y[end], y[t]) == 0) break;
}
if (end == t) {
strcpy(y[current],y[t]);
current++;
}
}
y[current] = 0;
printf("%s",y);
}
I have written a smalll routine for it .Does not seems to be worked .Any one have any suggestion where i am going wrong?
The other answers you got work fine for a small number strings (your example code only has 4). But, if you're comparing a large number this will be quite slow since you're doing n^2 comparisons. I'd suggest first splitting the string into an array of strings, then sorting the array using qsort(). In a sorted array all duplicates are guaranteed to be adjacent. This reduces the time from n^2 to n log n -- the time required to sort.
I would split the string array using strtok (see the man page).
So I would have something like this
char x[100]="Amit Hanish Mahesh Amit";
/* Preparing the result string */
size_t sz_result = sizeof(char) * (strlen(x) + 1);
char* result = (char*) malloc( sz_result );
result[0] = '\0';
/* Parsing the string from one element to the other */
char* elm = strtok(x, " ");
while( (elm = strtok(NULL, " ")) != NULL )
{
...
You will have each element of the string to verify if they are unique.
Then I would use something like a hashmap (you can use the one from the glib) or I would put the read string element in a new string only if it is not already in.
Here is an example for the second solution:
...
/* Is the element already in the result string? */
if ( strstr(result, elm) == NULL )
{
/* Then we should add it */
snprintf( result, sz_result - 1, "%s %s", result, elm );
}
}
In the end if you want x to be modified, you simply copy result in x:
strncpy( x, result, 99 );
Here is a sample code (not optimised, not using the strn* primitives, etc.)
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char x[100]="Amit Hanish Mahesh Amit";
/* Preparing the result string */
size_t sz_result = sizeof(char) * (strlen(x) + 1);
char* result = (char*) malloc( sz_result );
result[0] = '\0';
/* Parsing the string from one element to the other */
char* elm = strtok(x, " ");
if (elm != NULL) strcpy(result, elm);
while( (elm = strtok(NULL, " ")) != NULL )
{
/* Is the element already in the result string? */
if ( strstr(result, elm) == NULL )
{
/* Then we should add it */
strcat( result, " " );
strcat( result, elm );
}
}
strcpy( x, result );
fprintf( stdout, "Result: %s\n", x );
}
To remove duplicates from an array without preserving the order of elements:
sort the array
copy unique elements to the beginning of the array
remove the tail with duplicate elements
int remove_duplicates(StringArray array) {
if (! (array and array->items)) return 0; // empty array or NULL
StringArray_sort(array); // sort
// unique_copy()
String result = array->items, last = array->items + array->size;
for (String first = array->items; first != last; ++result) {
String_copy(result, first); // copy first to result
for (String prev = first; ++first != last and String_cmp(prev, first) == 0;)
{ /* skip adjacent equal items */ }
}
// shrink
return StringArray_remove(array, result, last);
}
Example
int main() {
char text[] = "Mahesh Amit Hanish Amit";
StringArray array = split(text, sizeof(text));
StringArray_dump(array, "<"); // print array before removing duplicates
if (remove_duplicates(array) < 0)
perror("error remove_duplicates(), OS error if any");
StringArray_dump(array, ">"); // print it after
StringArray_destroy(array);
return 0;
}
Where split() is:
StringArray split(const char* text, size_t size) {
if (! (text and text[size-1] == '\0')) return NULL;
StringArray array = StringArray_create();
if (! array) return NULL;
size_t n = -1;
for (const char* p = text; p != text+size; p += n+1) {
n = strcspn(p, " \t\n"); // find index of the next whitespace
if (n == 0) continue; // skip consecutive whitespace
// append characters in range [p, p+n)
// as a string to the array
const String string = String_create(p, n);
if (StringArray_append(array, string) < 0) {
String_destroy(string);
StringArray_destroy(array);
return NULL;
}
String_destroy(string);
}
return array;
}
Output
Mahesh<Amit<Hanish<Amit<
Amit>Hanish>Mahesh>
Full source code
I'm pretty sure, that the following line is not intended (assignment, not comparison)
if (end = t) {
See what happens, if you code a == and come back, if you still have problems.
Hint: Always code blanks around operators, so expressions are easier to read.
It's always fun to try to solve this kind of simple problems in C as exercise. Here's my take.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* strstrn(const char *haystack, const char *needle, size_t needle_len)
{
while((haystack = strchr(haystack, *needle)))
{
if (strncmp(haystack, needle, needle_len) == 0)
return (char *) haystack;
haystack++;
}
return NULL;
}
char* find_duplicate(const char* str, size_t len, size_t dup_len)
{
for(size_t i = 0; i < (len - dup_len); i++)
{
char* r = strstrn(str + i + 1, str + i, dup_len);
if(r) return r;
}
return NULL;
}
int main(int argc, char** argv)
{
if(argc < 3)
{
fprintf(stderr, "Usage: %s haystack dup_size\n", argv[0]);
return 1;
}
char* haystack = argv[1];
size_t len = atoi(argv[2]);
char* r;
while((r = find_duplicate(haystack, strlen(haystack), len)))
{
strcpy(r, r + len);
}
puts(haystack);
return 0;
}
/*
* C Program to Find the Frequency of Every Word in a
* given String
*/
#include <stdio.h>
#include <string.h>
void main()
{
int count = 0, c = 0, i, j = 0, k, space = 0;
char str[100], p[50][100], str1[20], ptr1[50][100];
printf("Enter the string\n");
scanf(" %[^\n]s", str);
printf("string length is %d\n", strlen(str));
for (i = 0;i<strlen(str);i++)
{
if ((str[i] == ' ')||(str[i] == ', ')||(str[i] == '.'))
{
space++;
}
}
for (i = 0, j = 0, k = 0;j < strlen(str);j++)
{
if ((str[j] == ' ')||(str[j] == 44)||(str[j] == 46))
{
p[i][k] = '\0';
i++;
k = 0;
}
else
p[i][k++] = str[j];
}
k = 0;
for (i = 0;i <= space;i++)
{
for (j = 0;j <= space;j++)
{
if (i == j)
{
strcpy(ptr1[k], p[i]);
k++;
count++;
break;
}
else
{
if (strcmp(ptr1[j], p[i]) != 0)
continue;
else
break;
}
}
}
for (i = 0;i < count;i++)
{
for (j = 0;j <= space;j++)
{
if (strcmp(ptr1[i], p[j]) == 0)
c++;
}
printf("%s -> %d times\n", ptr1[i], c);
c = 0;
}
}