How do I compare strings in an Array of Struct? - c

I am trying to compare strings that I have gotten from a struct Array and am trying to see if both are equal before I print it out.
int index;
for (int i = 0; strlen((cityArr+i)->cityname) != 0; i++) {
for (int j = 0; strlen((cityArr+j)->cityname) != 0; j++) {
if (strcmp(cityArr[i].cityname, cityArr[j].cityname) == 0) {
index = i;
}
}
}
printf("%s\n", cityArr[index].cityname);
So the information I have basically means that I should just print a duplicate right?
However, my output is:
San Jose
Fort Worth
San Diego
Pittsburgh
Omaha
Stockton
Austin
New York
Corpus Christi
Fort Worth
I believe that the only city that should be printed is Fort Worth, not all the cities (which is the case here).
Someone identified my question as a duplicate -
I read through the topic, but I somewhat understand how does strcmp work.
strcmp is returns a value of 0 if the strings are equal, but here I am trying to print out the equal city names, but instead it prints out every city in the array I am working on.

What you are doing is good but you miss one thing, when i will be equal to j.
To resolve this problem you can just do this :
int index;
for (int i = 0; strlen((cityArr+i)->cityname) != 0; i++) {
for (int j = 0; strlen((cityArr+j)->cityname) != 0; j++) {
if (i == j) {
continue;
}
if (strcmp(cityArr[i].cityname, cityArr[j].cityname) == 0) {
index = i;
}
}
}
printf("%s\n", cityArr[index].cityname);
With this, if i is equal j, the second for will pass to the next iteration without testing if city names are the same.

Related

C Problems with a do while loop in a code that delete duplicate chars

I'm a beginner programmer that is learning C and I'm doing some exercises on LeetCode but I ran with a problem with today's problem, I'm going to put the problem bellow but my difficult is on a do while loop that I did to loop the deleting function if there are adjacent duplicates, my code can delete the duplicates on the first iteration, but it's not looping to do any subsequent tasks, if anyone could help my I would be grateful.
The LeetCode Daily Problem (10/11/2022):
You are given a string s consisting of lowercase English letters. A duplicate removal consists of choosing two adjacent and equal letters and removing them.
We repeatedly make duplicate removals on s until we no longer can.
Return the final string after all such duplicate removals have been made. It can be proven that the answer is unique.
Example 1:
Input: s = "abbaca"
Output: "ca"
Explanation:
For example, in "abbaca" we could remove "bb" since the letters are adjacent and equal, and this is the only possible move. The result of this move is that the string is "aaca", of which only "aa" is possible, so the final string is "ca".
Example 2:
Input: s = "azxxzy"
Output: "ay"
Constraints:
1 <= s.length <= 105
s consists of lowercase English letters.
My code (testcase: "abbaca"):
char res[100]; //awnser
char * removeDuplicates(char * s){
//int that verifies if any char from the string can be deleted
int ver = 0;
//do while loop that reiterates to eliminate the duplicates
do {
int lenght = strlen(s);
int j = 0;
int ver = 0;
//for loop that if there are duplicates adds one to ver and deletes the duplicate
for (int i = 0; i < lenght ; i++){
if (s[i] == s[i + 1]){
i++;
j--;
ver++;
}
else {
res[j] = s[i];
}
j++;
}
//copying the res string into the s to redo the loop if necessary
strcpy(s,res);
} while (ver > 0);
return res;
}
The fuction returns "aaca".
I did some tweaking with the code and found that after the loop the ver variable always return to 0, but I don't know why.
I see two errors
res isn't terminated so the strcpy may fail
You have two definitions of int ver so the one being incremented is not the one being checked by while (ver > 0); In other words: The do-while only executes once.
Based on your code it can be fixed like:
char res[100]; //awnser
char * removeDuplicates(char * s){
//int that verifies if any char from the string can be deleted
int ver = 0;
//do while loop that reiterates to eliminate the duplicates
do {
int lenght = strlen(s);
int j = 0;
ver = 0; // <--------------- Changed
//for loop that if there are duplicates adds one to ver and deletes the duplicate
for (int i = 0; i < lenght ; i++){
if (s[i] == s[i + 1]){
i++;
j--;
ver++;
}
else {
res[j] = s[i];
}
j++;
}
res[j] = '\0'; // <---------------- Changed
//copying the res string into the s to redo the loop if necessary
strcpy(s,res);
} while (ver > 0);
return res;
}

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 keep the rest of an array of strings in C from filling with junk?

I'm working on a practice program where the user inputs a list of names. I've got the array of strings set to 50 long to give the user plenty of space, but if they are done, they can type 'quit' to stop typing. how can i keep the rest of the array from filling with junk or possibly shrink it to fit only the entered list.
#include <stdio.h>
#include <string.h>
int main()
{
char list[50][11];
char temp[11];
int index;
printf("Input a list of names type 'quit' to stop\n")
for(index = 0; index < 50; index++)
{
scanf(" %10s", temp);
if(strcmp(temp, "quit") != 0)
{
strcpy(list[index], temp);
}
else
{
index = 50;
}
}
for(int index = 0; index < 50; index++)
{
puts(list[index]);
}
return 0;
}
IMO this is a Zen of Programming question, and UnholySheep is prodding you to think in the right direction.
What is Junk? You have told the computer you need a list of 50 things, but you didn't tell it what to put in all of those list entries. So the computer just uses whatever memory it has lying around, and the odds of a particular byte being whatever value you decide is Not Junk is something like 1:256.
Of course, the Zen here is not the answer to the question "What is Junk", but rather understanding that there is Junk and Not Junk, and the only Not Junk is that which you have arranged for to exist.
So, if you don't know that a memory address does not contain Junk, then it does.
The solution to your programming question then, is to keep track of how many list entries are Not Junk. There are two common approaches used in C for this:
keep track of the length of your list, or
put a special value at the end of your list
how can i keep the rest of the array from filling with junk (?)
1) Use index. Simply keep track of how much was used. Do not access the unused portion of the array
for(int i = 0; i < index; i++) {
puts(list[i]);
}
2) Mark the next unused with a leading null character.
if (index < 50) list[index][0] = '\0';
for(int i = 0; i < 50 && list[i][0]; i++) {
puts(list[i]);
}
3) Re-architect: use a right-sized allocation array (below), a link-list, etc.
or possibly shrink it to fit only the entered list (?)
Once an array is defined, its size cannot change.
Yet a pointer to an allocated memory can be re-allocated.
Here list is a pointer to array 11 of char
char (*list)[11] = malloc(sizeof *list * 50); // error checking omitted for brevity
....
// fill up to 50
....
list = realloc(sizeof *list * index); // error checking omitted for brevity
just keep a count of entered values
int count = 0;
printf("Input a list of names type 'quit' to stop\n")
for(index = 0; index < 50; index++)
{
scanf(" %10s", temp);
if(strcmp(temp, "quit") != 0)
{
strcpy(list[index], temp);
count++;
}
else
{
index = 50;
}
}
for(int index = 0; index < count; index++)
{
puts(list[index]);
}

How do I check if there is an element in a Matrix?

I'm Trying to check in my matrix of dimension [10][10], which spots are available to store data (String) there and which are occupied.
The code basically goes through the whole matrix and checks every spot.
I have tried using the strlen and != NULL but everything just prints that the spot is free.
char parque[10][10];
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++) {
parque[i][j] = "";
}
}
parque[5][5]="f47ac10b-58cb-4372-a567-0e02b2c3d499,ANR";
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++) {
if(parque[i][j] != "") {
printf("The Spot [%d][%d] is taken",i,j);
} else {
printf("The Spot [%d][%d] is free",i,j);
}
}
}
Basically the spot [5][5] should print that it's taken, at least that's what I want it to do...
Thanks in advance!
Your declaration
char parque[10][10];
declares a two-dimensional array of char. If you compile your code with a strict compiler, you'll get an error:
error: assignment makes integer from pointer without a cast [-Wint-conversion]
parque[i][j] = "";
^
What you did mean is to make an array of pointers to const char, like here:
const char* parque[10][10];
Then your program will say that The Spot [5][5] is taken.
You can't use !=. You need to use strcmp. And, of course, you need to initialize your array content before iterating it and using its values to compare with "" string.
This condition:
if(parque[i][j] != "")
Will become:
if (strcmp(parque[i][j], ""))

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