C Comparing 2 strings turned into memory allocation issue - c

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.)

Related

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 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;
}

How do I compare strings in an Array of Struct?

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.

Assigning point to customer C programming

I would like to get assistance in my coding. I created a customer loyalty system using C (using file) and now I need to assign some called points to my customer, but what happenned is it will not assign any points to them.
{
for (int i = 0; i < (count / 3); i++)
{
fscanf(reward_file, "%s\n%s\n%d\n", user[i].Username, user[i].Password, &user[i].Points);
if (Point = user[i].Points)
{
strcpy(user[i].Points, Reward);
Point = Point + Reward;
printf("%d", Point);
system("pause");;
}
}
fclose(reward_file);
FILE *new_file = fopen("CustomerRegistration.txt", "w");
for (int i = 0; i < NumOfCust; i++)
{
fprintf(new_file, "%s\n%s\n%d\n", user[i].Username, user[i].Password, user[i].Points);
}
fclose(new_file);
printf("You Have Successfully Added Your Point!!!\n");
printf("You Will be Redirected Back to Customer Privilege Menu");
system("TIMEOUT \t 5");
}
I am using struct for my customer and here is the code
struct USER
{
char Username[255];
char Password[255];
int Points;
};
struct USER user[100];
Data is obtained from a function called "Login"
FILE *LOGINFILE = fopen("CustomerRegistration.txt", "r");
if (LOGINFILE)
{
system("cls");
printf("!!!Hello Customer!!!\n");
printf("Please type in your Username and Password\n");
printf("Username\t: ");
//while ((c = getchar()) !='\n');
gets(UN);
printf("Password\t: ");
gets(Pswd);
I also assigned global variable called "Point"
int Point = 0;
Your help will be highly appreciated.
From what I am understanding from your posted code you want to add a Reward to the Customer Points.
Firstly you just need to add to user.Points the Reward, using strcpy makes no sense because that function is used for copying strings.
that if( Point = user[i].Points ) also makes no sense firstly because C equality condition is represented by a double equal sign ( "==" ) and you don't need to make that check.
The .Points member is an int and Reward is also an int ,so you can do arithmethic operations and there is no need to use another Point auxiliar.
for (int i = 0; i < (count / 3); i++)
{
fscanf(reward_file, "%s\n%s\n%d\n", user[i].Username, user[i].Password, &user[i].Points);
user[i].Points += Reward;
printf("%d", user[i].Points);
system("pause");;
}
.....
the first loop:
for (int i = 0; i < (count / 3); i++)
the second loop
for (int i = 0; i < NumOfCust; i++)
if NumOfCust is greater than (count/3)) you'll get unitialized values on CustomerRegistration.txt. I can't see the values of those variables, but make sure it doesn't happen. The best would be to use the last value of i in the first loop to the stop condition for the second loop.

C remove duplicate char from array

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.

Resources