Copying strings between vectors of strings in C - 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

Related

Using strcmp and strcpy to sort province’s name in alphabetical order

I am trying to implement strcmp and strcpy to re-arrange names in alphabetical order and there is an issue with my name array initialization.
The state array cannot be printed out on the console as expected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char sort(char [], char []);
int main() {
char strStates[8] = {
'Ontario', 'Quebec', 'Manitoba', 'Alberta',
'British Colombia', 'Nova Scotia', '\0'
};
char strSorted[] = { '\0' };
int x = 0;
printf("\nThe list of states before being sorted in alphabetical order: %s", strStates);
for (x = 0; x < 7; x++) {
printf("\n%s", strStates);
}
sort(strStates[x], strSorted[x]);
printf("\nThe list of states sorted alphabetically are: ");
for (x = 0; x < 4; x++) {
printf("\n%s", strStates[x]);
}
return 0;
}
char sort(char string1[], char string2[]) {
int x, y = 0;
for (x = 0; x < 3; x++) {
for (y = 1; y < 4; y++) {
if (strcmp(string1[x], string1[y]) > 0) {
strcpy(string2[y], string1[x]);
strcpy(string1[x], string1[y]);
strcpy(string[y], string2[y]);
}
}
}
}
You declared a character array of 8 characters
char strStates[8] = {'Ontario', 'Quebec', 'Manitoba', 'Alberta','British Colombia','Nova Scotia','\0'};
and trying to initialize it with multibyte character constant as for example 'Ontario' that have implementation defined values.
It seems you want to declare an array of string literals. In this case you should write for example
const char * strStates[] =
{
"Ontario", "Quebec", "Manitoba", "Alberta", "British Colombia","Nova Scotia"
};
Also it is a bad idea yo use magic numbers like 8
char strStates[8] = //...
or 7
for (x = 0; x < 7; x++)
or 4
for (x = 0; x < 4; x++)
This makes the code unclear.
You can determine the size of the declared array as shown above the following way
const char * strStates[] =
{
"Ontario", "Quebec", "Manitoba", "Alberta", "British Colombia","Nova Scotia"
};
const size_t N = sizeof( strStates ) / sizeof( *strStates );
As a result for example the for loop that outputs elements of the array can look like
puts( "The list of states before being sorted in alphabetical order:" );
for ( size_t i = 0; i < N; i++) {
puts( strStates[i] );
}
The array strSorted declared like
char strSorted[] = {'\0'};
is not used in your program. Remove the declaration.
This call of the function sort
sort(strStates[x], strSorted[x]);
does not make sense. The argument expressions have the type char while the function expects arguments of the type char *.
The function sort can be declared the following way
void sort( const char *[], size_t );
and called like
sort( strStates, N );
The function definition that implements the bubble sort method can look like
void sort( const char * s[], size_t n )
{
for ( size_t sorted = 0; !( n < 2 ); n = sorted )
{
for ( size_t i = sorted = 1; i < n; i++ )
{
if ( strcmp( s[i], s[i-1] ) < 0 )
{
const char *tmp = s[i];
s[i] = s[i-1];
s[i-1] = tmp;
sorted = i;
}
}
}
}
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
void sort( const char * s[], size_t n )
{
for (size_t sorted = 0; !( n < 2 ); n = sorted)
{
for (size_t i = sorted = 1; i < n; i++)
{
if (strcmp( s[i], s[i - 1] ) < 0)
{
const char *tmp = s[i];
s[i] = s[i - 1];
s[i - 1] = tmp;
sorted = i;
}
}
}
}
int main( void )
{
const char *strStates[] =
{
"Ontario", "Quebec", "Manitoba", "Alberta", "British Colombia","Nova Scotia"
};
const size_t N = sizeof( strStates ) / sizeof( *strStates );
puts( "The list of states before being sorted in alphabetical order:" );
for (size_t i = 0; i < N; i++) {
puts( strStates[i] );
}
sort( strStates, N );
puts( "\nThe list of states sorted alphabetically are:" );
for ( size_t i = 0; i < N; i++) {
puts( strStates[i] );
}
}
The program output is
The list of states before being sorted in alphabetical order:
Ontario
Quebec
Manitoba
Alberta
British Colombia
Nova Scotia
The list of states sorted alphabetically are:
Alberta
British Colombia
Manitoba
Nova Scotia
Ontario
Quebec
"...there is an issue with my name array initialization."
There are other issues additional to the array initialization....
Note: Single quotes in C depict a char. Use double quotes.. Change:
'Ontario'
to
"Ontario"
everywhere.
Additionally the \0 as the last element in the array is not necessary. Each "..." string contains its own null terminator.
Array initialization: arrays must be sized to contain the number of visible characters plus one additional byte for null terminator - for the longest string in the array.
Change
char strStates[8] = {'Ontario', ..., 'Nova Scotia','\0'};
To (including 2D array notation)
char strStates[][18] = {"Ontario", ..., "Nova Scotia"};//British Columbia (17 + 1)
^ ^ " " "
|longest string in collection
Or to this (avoids needing to know longest string in array.)
char *strStates[] = {"Ontario", ..., "Nova Scotia"};
For the comparison question, the following is a minimal example of how you can do that, using strcmp() implementation of compare function in conjunction with the qsort() function:
int comp(const void* a, const void* b);
int main(void)
{
char strStates[][18] = {"Ontario", "Quebec", "Manitoba", "Alberta","British Colombia","Nova Scotia"};
qsort(strStates, size, 18, comp);
return 0;
}
int comp(const void* a, const void* b) {
const char* aa = (const char*)a;
const char* bb = (const char*)b;
return strcmp(aa, bb);
}

Checking for duplicate letters in an array in C

I'm wondering why my duplicate check is giving me wrong output. The idea is to built a nested loop, that compares every following letter in an array, with the initial loop's one. However, if I print the results, the function gives back true when A = K e.g. and I don't understand that behaviour. Anyone able to explain what's happening here?
for (int n = 0; n < strlen(argv[1]) ; n++)
{
for (int i = 0; i < strlen(argv[1]) ; i++)
{
if (argv[1][n] == argv[1][i + 1])
{
printf("argv[1][n] = %c\n", argv[1][n]);
printf("argv[1][i] = %c\n", argv[1][i]);
printf("Error.\n");
return 0;
}
}
}
A more efficient way to check for duplicate chars in a string. Only requires one for-loop instead of a nested pair of loops. Assumes an 8-bit char - hence 256 as array size.
size_t table[256] = {0};
size_t positions[256] = {0};
const char* sz = argv[1];
const size_t len = strlen(argv[1]);
for (size_t i = 0; i < len; i++)
{
unsigned char index = (unsigned char)(sz[i]);
table[index]++;
if (table[index] > 1)
{
printf("duplicate char %c found at index %d. Originally seen at index %d\n", sz[i], i, (int)(positions[index]));
return 0;
}
else
{
positions[index] = i;
}
}
These for loops
for (int n = 0; n < strlen(argv[1]) ; n++)
{
for (int i = 0; i < strlen(argv[1]) ; i++)
{
if (argv[1][n] == argv[1][i + 1])
{
//...
}
}
}
do not make a sense because argv[1][n] can be the same letter at the same position as argv[1][i+1] because the inner loop starts from 0.
Also you are outputting a letter at position i
printf("argv[1][i] = %c\n", argv[1][i]);
but in the preceding if statement you are checking a letter at the position i + 1.
The loops can look the following way
for ( size_t i = 0, n = strlen( argv[1] ); i < n ; i++ )
{
for ( size_t j = i + 1; j < n; j++ )
{
if ( argv[1][i] == argv[1][j] )
{
printf( "argv[1][i] = %c\n", argv[1][i]);
printf( "argv[1][j] = %c\n", argv[1][j]);
printf("Error.\n");
return 0;
}
}
}
Instead of the inner loop you could use the standard C function strchr. Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
int unique( const char *s )
{
while ( *s && !strchr( s + 1, *s ) ) ++s;
return *s == '\0';
}
int main(void)
{
char *s = "12345";
printf( "\"%s\" -> %d\n", s, unique( s ) );
s = "12341";
printf( "\"%s\" -> %d\n", s, unique( s ) );
return 0;
}
The program output is
"12345" -> 1
"12341" -> 0
You may call the function passing as an argument the command line argument argv[1]. For example
If ( !unique( argv[1] ) ) puts( "Error." );
Why A = K is because you are printing the i-th index printf("argv[1][i] = %c\n", argv[1][i]); when you are checking i+1th index if (argv[1][n] == argv[1][i + 1]). You are printing the wrong character that is checked with your if statement.
Also, be careful on that i+1 and your loop condition.

how to compare two 2 d string without using strcmp

I have data file in which some data is kept.
example: welcome user HII if while
I have made 2D character array to store all the keywords in c.
now I want two know if the data file contain the keyword or not.
enter code here
for(i=0;i<32;i++)
for(j=0;j<no_of_words_in_file;j++)
if(k[i]==t[j])
printf("%s is keyword",t[j]);
here the k[i] represents the 2D character array where all the keywords in c are stored and t[i] represents the 2D character array where all the words of file are stored.
I want to compare these 2D arrays without using strcmp.
To compare two strings without using standard C functions you can use a loop like that
#include <stdio.h>
int main(void)
{
char key[] = "while";
char word1[] = "while";
char word2[] = "when";
size_t i = 0;
while ( key[i] != '\0' && key[i] == word1[i] ) ++i;
int equal = key[i] == word1[i];
printf( "key == word1: = %d\n", equal );
i = 0;
while ( key[i] != '\0' && key[i] == word2[i] ) ++i;
equal = key[i] == word2[i];
printf( "key == word2: = %d\n", equal );
return 0;
}
The program output is
key == word1: = 1
key == word2: = 0
Or you can write a separate function. For example
#include <stdio.h>
int equal( const char *s1, const char *s2 )
{
while ( *s1 != '\0' && *s1 == *s2 )
{
++s1; ++s2;
}
return *s1 == *s2;
}
int main(void)
{
enum { N = 10 };
char key[][N] ={ "if", "while" };
const size_t N1 = sizeof( key ) / sizeof( *key );
char words[][N] = { "welcome", "user", "HII", "if", "while" };
const size_t N2 = sizeof( words ) / sizeof( *words );
for ( size_t i = 0; i < N2; i++ )
{
for ( size_t j = 0; j < N1; j++ )
{
if ( equal( key[j], words[i] ) )
{
printf( "\"%s\" == \"%s\"[%zu]\n", key[j], words[i], i );
}
}
}
return 0;
}
the program output is
"if" == "if"[3]
"while" == "while"[4]

Splitting a string into chunks.

I'm trying to split a string into chunks of 6 using C and I'm having a rough time of it. If you input a 12 character long string it just prints two unusual characters.
#include <stdio.h>
#include <string.h>
void stringSplit(char string[50])
{
int counter = 0;
char chunk[7];
for (unsigned int i = 0; i < strlen(string); i++)
{
if (string[i] == ' ')
{
continue;
}
int lastElement = strlen(chunk) - 1;
chunk[lastElement] = string[i];
counter++;
if (counter == 6)
{
printf(chunk);
memset(chunk, '\0', sizeof chunk);
counter = 0;
}
}
if (chunk != NULL)
{
printf(chunk);
}
}
int main()
{
char string[50];
printf("Input string. \n");
fgets(string, 50, stdin);
stringSplit(string);
return(0);
}
I appreciate any help.
Your problem is at
int lastElement = strlen(chunk) - 1;
Firstly, strlen counts the number of characters up to the NUL character. Your array is initially uninitialized, so this might cause problems.
Assuming your array is filled with NULs, and you have, let's say, 2 characters at the beginning and you are looking to place the third one. Remember that your 2 characters are at positions 0 and 1, respectively. So, strlen will return 2 (your string has 2 characters), you subtract one, so the lastElement variable has the value 1 now. And you place the third character at index 1, thus overwriting the second character you already had.
Also, this is extremely inefficient, since you compute the number of characters each time. But wait, you already know how many characters you have (you count them in counter, don't you?). So why not use counter to compute the index where the new character should be placed? (be careful not to do the same mistake and overwrite something else).
The function is wrong.
This statement
int lastElement = strlen(chunk) - 1;
can result in undefined behavior of the function because firstly the array chunk is not initially initialized
char chunk[7];
and secondly after this statement
memset(chunk, '\0', sizeof chunk);
the value of the variable lastElement will be equal to -1.
This if statement
if (chunk != NULL)
{
printf(chunk);
}
does not make sense because the address of the first character of the array chunk is always unequal to NULL.
It seems that what you mean is the following.
#include <stdio.h>
#include <ctype.h>
void stringSplit( const char s[] )
{
const size_t N = 6;
char chunk[N + 1];
size_t i = 0;
for ( ; *s; ++s )
{
if ( !isspace( ( unsigned char )*s ) )
{
chunk[i++] = *s;
if ( i == N )
{
chunk[i] = '\0';
i = 0;
puts( chunk );
}
}
}
if ( i != 0 )
{
chunk[i] = '\0';
puts( chunk );
}
}
int main(void)
{
char s[] = " You and I are beginners in C ";
stringSplit( s );
}
The program output is
Youand
Iarebe
ginner
sinC
You can modify the function such a way that the length of the chunk was specified as a function parameter.
For example
#include <stdio.h>
#include <ctype.h>
void stringSplit( const char s[], size_t n )
{
if ( n )
{
char chunk[n + 1];
size_t i = 0;
for ( ; *s; ++s )
{
if ( !isspace( ( unsigned char )*s ) )
{
chunk[i++] = *s;
if ( i == n )
{
chunk[i] = '\0';
i = 0;
puts( chunk );
}
}
}
if ( i != 0 )
{
chunk[i] = '\0';
puts( chunk );
}
}
}
int main(void)
{
char s[] = " You and I are beginners in C ";
for ( size_t i = 3; i < 10; i++ )
{
stringSplit( s, i );
puts( "" );
}
}
The program output will be
You
and
Iar
ebe
gin
ner
sin
C
Youa
ndIa
rebe
ginn
ersi
nC
Youan
dIare
begin
nersi
nC
Youand
Iarebe
ginner
sinC
YouandI
arebegi
nnersin
C
YouandIa
rebeginn
ersinC
YouandIar
ebeginner
sinC

Iterate through a string that's on an array in 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).

Resources