Iterate through a string that's on an array in C - c

I have a code like this:
char* s[4][10] = { "abc\0", "aab\0", "cbb\0" };
a want to type a character, like.. 'a', and iterate through the array of strings, check on each string if there's 'a' on it, and then count how many there's on it..
In this case, what I wanted to get is "abc" : 1, "aab" : 2, "cbb" : 0 ...
how can I do the loops to get this result?

char input = '\0';
scanf("%c", &input);
int i, j;
for(i=0; i<4; i++)
{
int count = 0;
for(j=0;j<10;j++)
{
if(s[i][j] == input) count++;
}
printf("%s : %d", s[i], count);
}
although please note, that simply copying and pasting will not teach you anything.

Here is a demonstrative program that shows how you can deal with different declarations of arrays
#include <stdio.h>
int main(void)
{
char* s[4][10] = { { "abc", "aab", "cbb" } };
for ( int i = 0; i < 4; i++ )
{
for ( int j = 0; j < 10; j++ )
{
if ( s[i][j] )
{
size_t count = 0;
for ( char *p = s[i][j]; *p != '\0'; ++p )
{
if ( *p == 'a' ) ++count;
}
printf( "\"%s\": %zu\n", s[i][j], count );
}
}
}
printf( "\n" );
char* t[4] = { "abc", "aab", "cbb" };
for ( char **p = t; *p != NULL; ++p )
{
size_t count = 0;
for ( char *q = *p; *q != '\0'; ++q )
{
if ( *q == 'a' ) ++count;
}
printf( "\"%s\": %zu\n", *p, count );
}
printf( "\n" );
char u[4][10] = { "abc", "aab", "cbb" };
for ( int i = 0; i < 4; i++ )
{
if ( u[i][0] != '\0' )
{
size_t count = 0;
for ( char *p = u[i]; *p != '\0'; ++p )
{
if ( *p == 'a' ) ++count;
}
printf( "\"%s\": %zu\n", u[i], count );
}
}
return 0;
}
The program output is
"abc": 1
"aab": 2
"cbb": 0
"abc": 1
"aab": 2
"cbb": 0
"abc": 1
"aab": 2
"cbb": 0
It seems that you mean either the second variant of the array declaration or the third variant of the array declaration. The first variant looks strange.:)
Take into account that string literals already contain terminating zero. So there is no sense to write, for example
"abc\0"
It is enough to write simply
"abc"
The sizeof( "abc" ) is equal to 4 due to the presence of the terminating zero.

#include <stddef.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
char s[10][4] = { "abc", "aab", "cbb" };
size_t i;
for (i = 0; i != sizeof(s) / sizeof(s[0]); i++) {
fprintf(stdout, "%zu: %s\n", i, s[i]);
}
return 0;
}
or
#include <stddef.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
char *s[4] = { "abc", "aab", "cbb" };
size_t i;
for (i = 0; i != 3; i++) {
fprintf(stdout, "%zu: %s\n", i, s[i]);
}
return 0;
}
Note that the original declaration
char* s[4][10] = { "abc\0", "aab\0", "cbb\0" };
had several errors:
char * instead of char
[4][10] instead of [10][4]
"abc\0" instead of "abc" (the trailing '\0' is implicit).

Related

applying cipher code given as argv to userinput

I am trying to write a function that takes in variables cipher, userinput, alphabet and outputs the replace letters. for example at execution it takes in an argument argv ZYXWVUTSRQPONMLKJIHGFEDCBA. requests a user to input anything then switches only the letters for example input aBc should output zYx
// function that takes in cipher(c), userinput(u) and alphabet(a) and outputs cipher text
void cipher_text(string c, string u, string a)
{
string result = u;
for (int i = 0; i < strlen(u); i++)
{
for (int k = 0; k < strlen(a); k++)
{
if (tolower(u[i]) == a[k])
{
if(islower(u[i]))
{
result[i] = tolower(c[k]);
printf("%s %s\n",result,c);
}
else
{
result[i] = toupper(c[k]);
}
}
}
}
// printf("ciphertext: %s\n", result);
}
with cipher as YUKFRNLBAVMWZTEOGXHCIPJSQD
and userinput as abcd
I was expecting yukf but got qidc
The problem of the function is this inner for loop
for (int k = 0; k < strlen(a); k++)
{
if (tolower(u[i]) == a[k])
{
if(islower(u[i]))
{
result[i] = tolower(c[k]);
printf("%s %s\n",result,c);
}
else
{
result[i] = toupper(c[k]);
}
}
}
You need to break it as soon as a letter is found in the string pointed to by the pointer a. Otherwise there can be a chain of changes.
Also using the function strlen is inefficient and redundant.
Instead of the for loop you could use standard function strchr.
The function can be declared and defined the following way
string cipher_text( string c, string u, string a )
{
for ( string p = u; *p != '\0'; p++ )
{
string pos = strchr( a, tolower( ( unsigned char )*p ) );
if ( pos != NULL )
{
size_t i = pos - a;
*p = islower( ( unsigned char )*p )
? tolower( c[i] )
: c[i];
}
}
return u;
}
Pay attention to that instead of the typedef name string it is better to use its underlaying type char *.
In this case the function can look the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char * cipher_text( const char *c, char *u, const char *a )
{
for (char *p = u; *p != '\0'; p++)
{
const char *pos = strchr( a, tolower( ( unsigned char )*p ) );
if (pos != NULL)
{
size_t i = pos - a;
*p = islower( ( unsigned char )*p )
? tolower( c[i] )
: c[i];
}
}
return u;
}
int main( void )
{
const char *c = "XYZ";
const char *a = "abc";
char u[] = "c_B_a";
puts( cipher_text( c, u, a ) );
}
The program output is
z_Y_x

C function for maniplulating string

I have written this exercise which should remove any chars in the first argument string which appear in the second string. But the result is a segmentation fault for the arguments below. Can any one explain to me what am I missing?
#include <stdio.h>
void squeez(char s1[], char s2[])
{
int i, j, k, match;
while (s1[i] != '\0') {
match = 0;
for (k = 0; s2[k] != '\0'; ++k) {
if (s1[i] == s2[k]) {
match = 1;
break;
}
}
if (match) {
i++;
} else {
s1[j++] = s1[i++];
}
}
s1[j] = '\0';
}
int main()
{
char s[] = "asdsffffsffsk";
char x[] = "sf";
squeez(s, x);
printf("%s %s", s, x);
return 0;
}
For starters the function should be declared the following way
char * squeez( char s1[], const char s2[] );
That is the second parameter should have the qualifier const because the string specified by this parameter is not changed in the function.
The function should follow the general convention of C standard string functions and return pointer to the result string.
Within the function variables i and j are not initialized and have indeterminate values. So even the first while loop
int i, j, k, match;
while (s1[i] != '\0') {
// ...
invokes undefined behavior.
Instead of the type int of these variables you should use the type size_t because the type int can be not large enough to store lengths of strings.
You should declare variables in minimum scopes where they are used.
Keeping your approach to the function definition it can look the following way as it is shown in the demonstrative program below.
#include <stdio.h>
char * squeez( char s1[], const char s2[] )
{
size_t i = 0, j = 0;
while ( s1[i] != '\0' )
{
int match = 0;
for ( size_t k = 0; !match && s2[k] != '\0'; ++k )
{
if ( s1[i] == s2[k] ) match = 1;
}
if ( !match ) s1[j++] = s1[i];
i++;
}
s1[j] = '\0';
return s1;
}
int main(void)
{
char s[] = "asdsffffsffsk";
char x[] = "sf";
puts( squeez( s, x ) );
return 0;
}
The program output is
adk
Also as the variable i is not used outside the while loop then the while loop could be substituted for a for loop where the variable i will be declared. For example
char * squeez( char s1[], const char s2[] )
{
size_t j = 0;
for ( size_t i = 0; s1[i] != '\0'; i++ )
{
int match = 0;
for ( size_t k = 0; !match && s2[k] != '\0'; ++k )
{
if ( s1[i] == s2[k] ) match = 1;
}
if ( !match ) s1[j++] = s1[i];
}
s1[j] = '\0';
return s1;
}
I noticed that the i and j are not initialized. In fact, your code is workable without the problem that I put forward. This is the code I tried.
#include <stdio.h>
void squeez(char s1[], char s2[])
{
int index1 = 0, position = index1, index2 = 0;
int match = 0;
while (s1[index1] != '\0')
{
match = 0;
for (index2 = 0; s2[index2] != '\0'; index2++)
{
if (s1[index1] == s2[index2])
{
match = 1;
break;
}
}
if (match)
index1++;
else
s1[position++] = s1[index1++];
}
s1[position] = '\0';
}
int main()
{
char s[] = "asdsffffsffsk";
char x[] = "sf";
squeez(s, x);
printf("%s %s", s, x);
return 0;
}

How to delete all characters from a string which are in another string?

I need to delete all letters from s1 which are in s2.
I can't understand what is wrong with my code:
#include <stdio.h>
#include <stdlib.h>
void squeeze(char s1[], char s2[])
{
int i,j;
i=j=0;
for(i; s2[i]!='\0'; i++) {
for (j; s1[j] != '\0'; j++) {
if (s1[j] == s2[i]) {
s1[j] = s1[j + 1];
--j;
}
}
}
}
int main()
{
char w1[] = "abcde";
char w2[] = "fghaj";
squeeze(w1,w2);
puts(w1);
return 0;
}
but the output is:
abcde
What should I repair?
For starters the variable j is not reset to 0 in the inner loop for each iteration of the outer loop.
Secondly if a character has to be removed then all characters after it are not being moved to the left one position. You are simply replacing the removed character with the next character in the string.
The function can look the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <string.h>
char * squeeze( char s1[], const char s2[] )
{
for ( char *p = s1, *q = s1; *q; ++p )
{
if ( !*p || !strchr( s2, *p ) )
{
if ( q != p )
{
*q = *p;
}
if ( *p ) ++q;
}
}
return s1;
}
int main( void )
{
char w1[] = "abcde";
char w2[] = "fghaj";
puts( squeeze( w1, w2 ) );
return 0;
}
The program output is
bcde
If you are not allowed to use standard string functions and pointers then the program can look the following way.
#include <stdio.h>
char * squeeze( char s1[], const char s2[] )
{
for ( size_t i = 0, j = 0; s1[j] != '\0'; ++i )
{
size_t k = 0;
while ( s2[k] != '\0' && s2[k] != s1[i] ) ++k;
if ( s2[k] == '\0' )
{
if ( j != i )
{
s1[j] = s1[i];
}
if ( s1[i] != '\0' ) ++j;
}
}
return s1;
}
int main( void )
{
char w1[] = "abcde";
char w2[] = "fghaj";
puts( squeeze( w1, w2 ) );
return 0;
}
The program output is the same as shown for the previous demonstrative program
bcde
Two problems in squeeze:
You need to reinitialize j to zero on every pass through the loop.
You need to copy the entire remained of the string one character to the left, not just the character following the one you want to remove.
I suggest you rewrite squeeze as:
void squeeze(char s1[], char s2[])
{
int i,j;
i=j=0;
for( ; s2[i]!='\0'; i++) {
for (j = 0; s1[j] != '\0'; j++) {
if (s1[j] == s2[i]) {
strcpy(s1+j, s1+j+1);
--j;
}
}
}
}
I see an issue here , your code is not entering this statement for some reason :
if (s1[j] == s2[i]) {
s1[j] = s1[j + 1];
--j;
}
your question might be why ? cause i and j are not set to 0 , try printing them and you will see that j will move to 4 but i is staying forever as 0
so as a start you can fix it by doing this
for(i=0; s2[i]!='\0'; i++) {
for (j=0; s1[j] != '\0'; j++) {
then you didn't copy the whole string and moved it back one step to rewrite over the found caracter , you only moved one caracter and left it blank
Exemple
input : abcde
output :b_cde
to fix this you have two methods :
use strcpy in order to move back one step the code
for(i=0; s2[i]!='\0'; i++) {
for (j=0; s1[j] != '\0'; j++) {
if (s1[j] == s2[i]){
strcpy(s1+j, s1+j+1);
--j;
}
}
or you can simply create the same function using a boucle for
for(i=0; s2[i]!='\0'; i++) {
for (j=0; s1[j] != '\0'; j++) {
if (s1[j] == s2[i]){
for (k=j;s1[k] != '\0';k++)
s1[k] = s1[k + 1];
--j;
}
}
#include <stdio.h>
#include <string.h>
int rem_str(char * porgstr, char * pdel) {
if (!porgstr || !pdel) {
return 0;
}
int i = 0;
int j = 0;
char tmp[256] = {0};
int len = strlen(pdel);
for (i = 0; i < len; i++) {
tmp[pdel[i]]++;
}
len = strlen(porgstr);
for (i = 0, j=0; i < len; i++) {
if(tmp[porgstr[i]] == 0) {
porgstr[j] = porgstr[i];
j++;
}
}
porgstr[j] = 0;
return 0;
}
int main () {
char * input1 = strdup("origional string passed to program");
char * input2 = strdup("sdel");
printf("Input before del : %s\n", input1);
rem_str(input1, input2);
printf("String after del : %s\n", input1);
return 0;
}
Output:
./a.out
Input before del : origional string passed to program
string after del : origiona tring pa to program

Copying strings between vectors of strings in C

I have an array of char pointers (string array), which contains some duplicate values. I've found an algorithm that truncates the array by removing its duplicate values.
Here is a code sample :
int i, j , k;
int n = 10;
char *teams[n];
for(i=0;i<n;i++){
for(j=i+1;j<n;){
if(*(team[j]==*(team[i])){
for(k=j;k<n;k++){
//strcpy(team[k], team[k+1]);
team[k] = team[k+1];
}
n--;
}else{
j++;
}
}
}
I've read that the only way to copy strings between string arrays is to use strcpy(s1, s2). But in my case I can't use it, because strcpy function permits to copy s2 into s1 only if s2 has a lenght equal or bigger than the lenght of s1. So how can I implement this algorithm if I can't put the string pointed by the pointer team[k+1] in team[k] ?
It seems you need to remove duplicated string representations instead of duplicated addresses to strings.
If so then this if statement (if to add missed closed parenthesis)
if( *(team[j] ) ==*( team[i] ) ){
compares only first characters of strings instead of comparing strings pointed to by the pointers.
In this loop
for(k=j;k<n;k++){
//strcpy(team[k], team[k+1]);
team[k] = team[k+1];
}
each time when a duplicates string is found there is copied the whole array of pointers. Moreover there is an attempt to access memory beyond the array in this statement when k is equal to n-1
team[k] = team[k+1];
^^^^
You can write a separate function that will "remove" duplicates. The function can for example return pointer after the last unique element in the modified array.
#include <stdio.h>
#include <string.h>
char ** unique( char *s[], size_t n )
{
size_t i = 0;
for ( size_t j = 0; j < n; j++ )
{
size_t k = 0;
while ( k < i && strcmp( s[k], s[j] ) != 0 ) ++k;
if ( k == i )
{
if ( i != j ) s[i] = s[j];
++i;
}
}
return s + i;
}
int main(void)
{
char * s[] = { "A", "B", "A", "C", "A" };
const size_t N = sizeof( s ) / sizeof( *s );
for ( size_t i = 0; i < N; i++ ) printf( "%s ", s[i] );
printf( "\n" );
char **p = unique( s, N );
size_t n = p - s;
for ( size_t i = 0; i < n; i++ ) printf( "%s ", s[i] );
printf( "\n" );
return 0;
}
The program output is
A B A C A
A B C
#include <stdio.h>
#include <string.h>
unsigned dedup(char **arr, unsigned count)
{
unsigned this, that ;
for(this=0;this<count;this++){
for(that=this+1;that<count;){
if( strcmp(arr[that], arr[this])) {that++; continue; }
#if PRESERVE_ORDER
memmove(arr+that, arr+that+1, (--count - that) * sizeof arr[that] );
#else
arr[that] = arr[--count];
#endif
}
}
return count; /* the count after deduplication */
}
char *array[] = { "one", "two", "three", "two", "one", "four", "five", "two" };
int main(void)
{
unsigned count, index;
count = dedup(array, 8);
for (index = 0; index < count; index++) {
printf("%s\n", array[index] );
}
return 0;
}
[UPDATED]: I added the PRESERVE_ORDER version

How to replace every specific character to another in a string C?

I program in C. I'm supposed to create a program which identifies what is the most common character in a string and what's the second most common character.
I'm not sure why, but it's not working. the program should put into an integer the location of it. Not a pointer but if the most common is str1[i] then it will put into an integer the value of i. And so in the second most common. If it is str1[j] than it should put into an integer the value of j. then, it's supposed to replace the most commons with the second most common. The replacement function works, there's probably a problem in the loops although I can't figure out what is it.
Here's what I have (assume all of the integers and strings are declared in the beginning):
void stringReplace(char str1[], char ch1, char ch2);
int main()
{
char str1[100];
char ch1, ch2;
int i, j, p, n, len, counter1, counter2, first, second, times;
printf("Please enter the string - maximum = 100 characters:\n");
printf("User input: ");
gets(str1);
len = strlen(str1);
for(i = 0 ; i < len ; i++)
{
counter1 = 0;
for(j = 0 ; j < len ; j++)
{
if(str1[i] == str1[j])
{
counter1++;
}
if(counter1 > counter2)
{
first = i;
}
}
counter2 = counter1;
} //character which shows up most - found.
counter2 = 0;
for(p = 0 ; p < len ; p++)
{
for(n = 0 ; n < len ; n++)
{
if(str1[p] == str1[n])
{
counter1++;
}
if(counter1 < first && counter1 > counter2)
{
second = p;
}
}
counter2 = counter1;
}
ch1 = str1[first];
ch2 = str1[second];
stringReplace(str1, ch1, ch2);
puts(str1);
return 0;
}
void stringReplace(char str1[], char ch1, char ch2)
{
int i, j, len;
len = strlen(str1);
for(i = 0 ; i <= len ; i++)
{
if(str1[i] == ch1)
{
str1[i] = ch2;
}
}
}
Where's the problem ?
So you want to find the n max numbers in a string, being n=2, right?
I did a little working example for you. The code differs slightly from yours but it works well.
#include <stdio.h>
int main(int argc, char* argv[])
{
char str[] = "Algorithms Are Funnnn!\0";
int i=0;
int offset=33;
int ocurrs[94] = {0}; //considering from 33 to 126 (valid chars - ASCII Table [0-127]).
int max[2]={0};
while(str[i])
ocurrs[str[i++]-offset]++;
for(i=0; i<94; i++)
if(ocurrs[i]>ocurrs[max[1]]){
max[0] = max[1];
max[1] = i;
}
else if(ocurrs[i]>ocurrs[max[0]])
max[0]=i;
printf("chars '%c'(%d times) and '%c'(%d times) occurred most.\n",
offset+max[1], ocurrs[max[1]], offset+max[0], ocurrs[max[0]]);
return 0;
}
Also, try to stay away from gets as it's totally unsafe.
If you want to grab 100 chars max, use this instead:
char buffer[100];
fgets(buffer, 100, stdin);
Regards.
Can't resist to find an answer with some loops, without the populate occurence technique.
Very fun to code.
#include <string.h>
#include <stdio.h>
int main( void ) {
char szInput[] = "ONE DOES NOT SIMPLY WALK INTO MORDOR!";
int len = strlen( szInput );
int MaxCountSoFar_1 = 0;
int MaxIndexSoFar_1 = -1;
int MaxCountSoFar_2 = 0;
int MaxIndexSoFar_2 = -1;
int i, j, CountThatOne;
for ( i = 0; i < len; ++i ) {
if ( szInput[ i ] == ' ' ) continue;
// count that char
CountThatOne = 1;
// don't start from 0, they are already "counted"
for ( j = i + 1; j < len; ++j ) {
if ( szInput[ i ] == szInput[ j ] ) ++CountThatOne;
}
if ( CountThatOne > MaxCountSoFar_1 ) {
// push old first max to new second max
MaxCountSoFar_2 = MaxCountSoFar_1;
MaxIndexSoFar_2 = MaxIndexSoFar_1;
// new first max
MaxCountSoFar_1 = CountThatOne;
MaxIndexSoFar_1 = i;
} else {
// catch second one, but not if equal to first
if ( CountThatOne > MaxCountSoFar_2 && szInput[ i ] != szInput[ MaxIndexSoFar_1 ] ) {
MaxCountSoFar_2 = CountThatOne;
MaxIndexSoFar_2 = i;
}
}
}
if ( MaxIndexSoFar_1 >= 0 ) {
printf( "Most seen char is %c, first seen at index %d\n", szInput[ MaxIndexSoFar_1 ], MaxIndexSoFar_1 );
if ( MaxIndexSoFar_2 >= 0 ) {
printf( "Second Most seen char is %c, first seen at index %d\n", szInput[ MaxIndexSoFar_2 ], MaxIndexSoFar_2 );
}
}
return 0;
}

Resources