C remove duplicate char from array - c

Somewhere in my program I get these outputs:
ee
or:
thht
Basically I want to remove the duplicates to obtain e or th. I got this code:
j = 0;
for (i = 1; i < strlen(erros); i++)
{
if (erros[j] != erros[i])
{
erros[j+1] = erros[i];
j++;
}
}
This code gives me e and tht. If in the first case its OK, in the second its not. I believe it is due because I don't have a sorted array.
Is there a way, without sorting the array and using the above code, to obtain the desired output?

You can create an array of flags, one for each possible character value. The first time you encounter a particular character value, set the flag. The next time you encounter that value, the flag will be set, indicating that you can remove that character.
Along the lines of (untested):
int flags[1 << CHAR_BIT];
memset(flags, 0, sizeof(flags));
j = 0;
for (i = 0; i < strlen(erros); i++)
{
erros[j] = erros[i]; // Always copy, it's simpler
if (!flags[erros[i]])
{
j++;
}
flags[erros[i]] = 1; // Always set the flag, it's simpler
}
erros[j] = '\0';
Note: You are forgetting to set the NULL terminator in your string.

Related

Simulate strrev() function, crazy output

I should simulate the operation of the strrev() function with an inscription from me. However, I don't understand why I have a series of special characters that don't make sense as output until you stop the program completely. I also tried to see if the problem was in the index "i" with the commented line of code, but it's ok. What could be the problem? thanks!
void strrev_new(char *s_to_rev) {
int i = 0;
int length = 0;
length = strlen(s_to_rev);
for (i = 0; i < length; i++) {
s_to_rev[length - i] = s_to_rev[i];
// printf("%d ----- %d\n", (length-i), i);
}
}
You have an off-by-one error, since strlen() returns the length of the string (e.g. 5 for hello), but the last index in the string is 4 (counting from 0).
Try
s_to_rev[length - 1 - i] = s_to_rev[i];
Your code has two problems. The first, brilliantly spotted by #AKX, is that you write starting from str[length] character instead of str[length-1] (in C array indexes start from 0).
The second problem is a consequence of the fact you are trying to reverse the string in place, that is without using a auxiliary array.
With the loop
for (i = 0; i < length; i++) {
s_to_rev[length - i] = s_to_rev[i];
}
you correctly start updating the last elements of the array. But as soon as you reach the half of the string, the characters at s_to_rev[i] are not the original ones anymore, as you updated them previously!
Try instead traversing half the string and swapping characters (just use a temporary char variable):
for (i = 0; i < length/2; i++) {
char tmp = s_to_rev[length - i -1],
s_to_rev[length - i -1] = s_to_rev[i];
s_to_rev[i] = tmp;
}

Check if a string is included in an array and append if not (C)

I have 2 arrays, one called 'edges' which contains a list of city names and another called cityNames which is initialised as an empty string.
What I would like to do is move through the edges array element by element and see if it is included in the cityNames array. If it is, move onto the next element in edges, if it isn't, append the value to the cityNames array.
The code below adds the edges[i].startCity to the cityNames array but it does not check for duplicates and I can't figure out why.
for (int i = 1; i < noEdges; i++) {
for (int j = 0; j < noCities; j++) {
if(strcmp(edges[i].startCity, cityNames[j].cityName) != 0) {
strcpy(cityNames[i].cityName, edges[i].startCity);
}
}
noCities += 1;
}
Thanks in advance
I will assume that:
edges is an array of structures of a known length noEdges, each structure containing a string (either a char pointer or a char array)
cityNames is an array of structures for which the size is at least the number of distinct name (it could be noEdges or the size of the edges array)
the cityNames structure contain a char array element for which the size is at least the longest name + 1 (+1 for the terminating null)
Then the following code could give the unique names:
noCity = 0;
for (int i = 0; i < noEdges; i++) {
int dup = 0; // expect edges[i].startCity not to be a duplicate
for (int j = 0; j < noCities; j++) {
if(strcmp(edges[i].startCity, cityNames[j].cityName) == 0) {
dup = 1; // got a duplicate
break; // no need to go further ...
}
}
if (dup == 0) { // not a duplicate: add it to cityNames
strcpy(cityNames[noCities].cityName, edges[i].startCity);
noCities += 1; // we now have one more city
}
}
}
A good idea to start with would be to ditch working with strings if you can (or at least manipulate strings when actually needed).
You could start off by assigning each city name a number, that way you have an array of ints which is quicker and easier to work with.
Scanning for duplicates becomes trivial as you would now only be comparing numbers.
When you need to display the actual text on screen or write the city names to file, you could use the indexes associated with the city names to retrieve the appropriate textual representation of the index. You could then replace the data type of your cityNames[] to ints. This makes each 'node' which the 'edges' connect a number instead of text.
char* actualCityNames[n]; //array holding all city names with duplicates, could be a file also
char* indexedCityNames[n];//array with indexed cities (in order of appearance in actualCityNames, i.e. not alphabetical order)
//indexedCityNames will most likely not use up N slots if duplicates occur
//this is why there is a second counter for the size of indexed cities
int indexedCount = 0;//number of unique city names
int duplicates = 0;
//loop for actualCityNames slots
for(int i=0; i<n; i++){
//loop for indexedCityNames
for(int j=0; j<indexedCount; j++){
//strcmp returns 0 if both strings are the same
if(strcmp(actualCityNames[i],indexedCityNames[j]) == 0){
//duplicate found, mark flag
duplicates = 1;
}
}
if(!duplicates){
strcpy(indexedCityNames[indexedCount],actualCityNames[I]);
indexedCount++;
}
duplicates = 0;
}
Your code snippet does not check for duplicates because in the inner loop the if statement appends startCity as soon as a first cityName is encountered that is not equal to the current startCity.
Moreover in this statement
strcpy(cityNames[i].cityName, edges[i].startCity);
^^^
there is used an incorrect index.
And the variable noCities shall be incremented only when a new startCity is appended.
Also the outer loop should start from the index equal to 0.
Rewrite the loops the following way
int noCities = 0;
for ( int i = 0; i < noEdges; i++ ) {
int j = 0;
while ( j < noCities && strcmp(edges[i].startCity, cityNames[j].cityName) != 0 ) {
++j;
}
if ( j == noCities ) strcpy(cityNames[noCities++].cityName, edges[i].startCity);
}

How do I replace all occurrences in an array with another array in C

I want to replace all occurrences in an array (string) with another array.
I have a code that:
stores the string in an array in which the replacing is to take place output[],
another array that stores the string to be searched for as replace[] and a third array called toBeReplacedBy and the replacing of the first occurrence works just fine but it skips the other occurrences in the output
for example:
replace[]:
abc
toBeReplacedBy[]:
xyz
output[]:
abcdefabc
becomes
xyzdefabc
but it should become:
xyzdefxyz
I suspect the problem lies with the replacer code :
//the replacer
for (i = 0; i<80; i++) {
if (output[i] == replace[i])
output[i] = toBeReplacedBy[i];
}
//debug purpose
puts("output[]:\n");
puts(output);
return 0;
}
What have I done wrong here and how could I get it to replace all occurrences in the array.
please be aware that I only wish to use stdio.h to do this
thabks in advance
Never iterate further than the array length. This leads to undefined and possibly dangerous behaviour. If you only expect strings, use something like:
int i = 0;
while(output[i] != '\0')
{
// your logic here
i++;
}
Additionally you want to check for concurrent appearances of the same characters. But in your code you only check the first three characters. Everything after that is undefinded behaviour, because you cannot know what replace[3] returns.
Something similar to this could work:
int i = 0;
int j = 0;
int k;
while(output[i] != '\0')
{
if (output[i] == replace[j])
j++;
else
j = 0;
// replace 3 with the array length of the replace[] array
if (j == 3)
{
for(k = i; j >= 0; k-- )
{
output[k] = toBeReplacedBy[j]
j--
}
j = 0;
}
i++;
}
But please check the array boundaries.
edit: Additionally as Nellie states using a debugger would help you to understand what went wrong. Go through your program step by step and look how and when values change.
First advice is to try to debug your program if it does not work.
for (i = 0; i<80; i++) {
if (output[i] == replace[i])
output[i] = toBeReplacedBy[i];
}
There are two problems in this loop.
The first is that are iterating until i is 80. Let's look what happens when i becomes 3. output[3] in case of abcdefabc is d, but what is replace[3]? Your replacement array had only 3 letters, so you have to go back in the replacement array once you finish with one occurrence of it in the original string.
The second is that you check letter by letter.
Say you original array, which you named output somehow was abkdefabc, first three letters do not match your replacement string, but you will check the first two letters they will match with the replacement's first two letters and you will incorrectly change them.
So you need to first check that the whole replacement string is there and only then replace.
You should use strlen() to know length of your array or iterate until you reach the end of a your array ('\0').
'\0' and strlen are only available for array of char.
Your loop should looks like this :
int i = 0;
int len = strlen(my_string);
while (i < len)
{
//logic here
i = i + 1;
}
OR
int i = 0;
while (my_string[i] != '\0')
{
// logic here
i = i + 1;
}

2D string array is storing '\0' when it encounters a word with more than one space or digit

I am pretty new to C programming. My program is supposed to take a string and move it into a 2D array. With the words either being separated by a white-space or a digit. This works perfectly fine if there is one space or digit separating it. However, as soon as there is more than one it starts adding '\0' to my array.
//Move the string into a 2D array
for(i = 0; i < total + 1; i++)
{
if(isalpha( *(tempString + i) ))
{
sortingArray[n][j++] = tempString[i];
input++;
}
else
{
sortingArray[n][j++] = '\0';
n++;
j = 0;
}
if(tempString[i] == '\0')
break;
}
This is a sample of what happens (n = number of rows placed)
./a.out "one more way"
5 inputs
before
one
more
way
After
one
more
way
You need to skip consecutive delimiters:
for(i = 0; i < total; i++)
{
if(isalpha(tempString[i]))
{
sortingArray[n][j] = tempString[i];
++j;
++input;
}
else
{
// skip consecutive delimiters
while (i < total && !isalpha(tempString[i]))
++i;
sortingArray[n][j] = '\0';
++j
++n;
j = 0;
}
}
Disclaimer: not verified by a compiler. Use caution!
I also took the liberty of some improvements to your original code.
there is no sense to check for \0 if you have the length of the string.
changed *(tempString + i) to the clear tempString[i]
moved the increments out of the larger expressions into their own full expression. It is clearer this way.
It's a simple logic failure for which a debugger is ideal for identifying.
Imagine you have the string "hello world".
It stores "hello" into sortingArray[0] easily enough. When it gets to the first space it increments n and starts looking for the next word. But the next character it finds is another space so it increments n again.
A slight change is required to your logic
if(isalpha( *(tempString + i) ))
{
sortingArray[n][j++] = tempString[i];
input++;
}
else if(j>0)
{
sortingArray[n][j++] = '\0';
n++;
j = 0;
}
Now the code will only increment n if the previous character was a letter (by virtue of j being more than 0). Otherwise if it doesn't care and will keep going.
You should also check to see if j is non-zero after the loop as that means there is a new entry in sortingArray that needs a NUL added.
One thing also to note is that the way you're doing the for loop is a little odd. You have this
for(i = 0; i < total + 1; i++)
but also this inside the loop
if(tempString[i] == '\0')
break;
Typically, the way to terminate the for loop would be to write it like this
for(i = 0; tempString[i]!='\0'; i++)
as that way you firstly don't care about the length of the string, but the loop will finish when it hits the NUL character.

C Comparing 2 strings turned into memory allocation issue

Let me start off by saying, I do realize there are a lot of questions with the exact same title, but I didn't find what I was looking for in any of them. I tried to write the following code, in order to errorcheck the user's input, so he wouldn't give 2 variables the same name. Needless to say, it failed, and that is why I am here. While printing the strings I was comparing out as strings, using printf("%s", temp[j].name); was working fine, the character-by-character printing was outputting a series of characters that, from what I know, shouldn't be there. I would like to know what this could all be about, and if there is anyway to solve it, so I can actually compare the 2, without using something from string.h
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#define ARRAYLENGTH 20
typedef struct{
char name[ARRAYLENGTH];
char type[ARRAYLENGTH];
char value[ARRAYLENGTH];
}variable;
int main(){
int amount = 3;
int i, j, k;
variable * varray;
variable * temp;
int flag;
int added = 1;
varray = malloc(amount*sizeof(variable));
if (varray == NULL){
printf("error");
return 1;
}
temp = malloc(amount*sizeof(variable));
if (temp == NULL){
printf("error");
return 1;
}
printf("Give the name of variable # 1 \n");
scanf("%s", varray[0].name);
for (i = 1; i < amount; i++){
flag = 0;
while (flag == 0){
printf("Give the name of variable # %d \n", i + 1);
scanf("%s", temp[i].name);
for (j = 0; j < added; j++){
for (k = 0; temp[i].name[k] != '\0'; k++){
printf("%c,", temp[i].name[k]);
}
printf("\n");
for (k = 0; temp[i].name[k] != '\0'; k++){
if (varray[j].name[k] != temp[i].name[k]){
flag = 1;
break;
}
if (varray[j].name[k] == temp[i].name[k]){
flag = 0;
}
}
}
if (flag == 0){
printf("The variable name you gave already exists, please choose another one. \n");
}
if (flag == 1){
for (j = 0; j < ARRAYLENGTH; j++){
varray[i].name[j] = temp[i].name[j];
}
}
if(flag == 1){
added +=1;
}
}
}
for (i = 0; i < amount; i++){
printf("%s \n", varray[i].name);
}
free(varray);
free(temp);
}
The code compiles without problem, but when I tried to run it, I found that, no matter what my, as a user, input was, the flag would always be 1 in the end. The block of code
printf("\n");
for (k = 0; k < ARRAYLENGTH; k++){
printf("%c,", temp[i].name[k]);
}
printf("\n");
And when the user input is the name John, outputs the following on Visual Studio 2013's Developer command prompt:
Give the name of variable # 1
John
Give the name of variable # 2
John
J,o,h,n,
The variable name you gave already exists, please choose another one.
Give the name of variable # 2
George
G,e,o,r,g,e,
Give the name of variable # 3
George
G,e,o,r,g,e,
G,e,o,r,g,e,
The variable name you gave already exists, please choose another one.
Give the name of variable # 3
John
J,o,h,n,
J,o,h,n,
John
George
John
What I am guessing this problem is about, is that the memory the system is allocating to temp and varray are already being used elsewhere. This errorcheck is crucial for a project I have to do, so I would appreciate any help I can get in solving this problem greatly. Thanks in advance,
LukeSykpe
The problem is with your printing logic.
The scanf function writes the user input into the array, followed by a terminating `\0' character. It does not know the size of your array (20), so it doesn't touch the part of the array that it doesn't actually write.
Instead of this:
for (k = 0; k < ARRAYLENGTH; k++){
write:
for (k = 0; temp[i].name[k] != '\0'; k++) {
Note that you don't need to check for running off the end of the array here. Instead, make sure that the user string is not too big for your array. See this for how to do that.
Edit : This post is not to answer the original question, but to answer a follow-up question posted in comments. I tried to incorporate this into the previous answer, but the owner refused. So here it is.
The problem with your varray comparisons is that, with the code you are showing at least, varray is never initialized. So
if (varray[j].name[k] != temp[i].name[k])
Is a bit like taking a random byte in memory, assigning it to a variable and doing this :
if (RandomByteValue != temp[i].name[k])
Which 90% of the time will be true thus setting your flag to 1.
Essentially, you're missing a
varray[i] = lastVariableGotFromUser
At the end of each main loop.
--- Edit : Added in minor corrections to general functionality ---
Try adding in this :
int added = 1;
Then change this :
for (j = 0; j < amount; j++){
with :
for (j = 0; j < added; j++){
and add in :
if (flag == 1){
// Your for loop
added += 1;
}
What was happening was that you iterated through fields of varray that were uninitialized, and contained random memory. With those modifications (If i didn't forget one, it should work. Try to always limit your loops to only the useful iterations. If you know you only have one variable added in, don't iterate through the 3 fields.
------- Last edit to correct a detail in his code -------
So, your whole :
for (k = 0; temp[i].name[k] != '\0'; k++){
Can be deleted. Now i also know that you don't want to use string.h, However, recoding a strcmp ain't all that complicated. Let's call it
int comp_str(str, str2) // Returns 1 if they don't match, zero if they do.
then just replace your whole for with :
if (comp_str(temp[i].name, varray[j].name) == 0) {
flag = 0;
break;
}
else
flag = 1;
You only want to set the flag when a whole string has been analyzed. So pass it to another function, act upon the return value, and it works! Generally slice your code up. Easier to act/think on. (and also avoids having things like varray[j].name[k] != temp[i].name[k] which is long an not so pleasing to read, in your code.)

Resources