#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *userfile, *pwfile, *usernamesPasswords, *readUsernamesPasswords;
char u, p, user[20][25], pass[20][20], userLine[25], passLine[20];
int i = 0;
int j = 0;
int userIndex = 0;
int passIndex = 0;
userfile = fopen("usernames.txt", "r");
pwfile = fopen("passwords.txt", "r");
if (userfile == NULL || pwfile == NULL) {
printf("Cannot open file \n");
exit(0);
}
u = fgetc(userfile);
while (u != EOF) {
if ( u != '\n'){
userLine[userIndex++] = u;
} else {
userLine[userIndex] = '\0';
strcpy(user[i], userLine);
userIndex = 0;
i++;
}
u = fgetc(userfile);
}
fclose(userfile);
p = fgetc(pwfile);
while (p != EOF) {
if ( p != '\n'){
passLine[passIndex++] = p;
} else {
passLine[passIndex] = '\0';
strcpy(pass[j], passLine);
passIndex = 0;
j++;
}
p = fgetc(pwfile);
}
fclose(pwfile);
usernamesPasswords = fopen("usernamesPasswords.txt", "w");
int w, k;
char newLine[1024];
for (w=0;w<20;w++) {
strcat(newLine, user[w]);
int q = strlen(newLine);
for (k=0;k<(25-q);k++) {
strcat(newLine, " ");
}
strcat(newLine, pass[w]);
strcat(newLine, "\n");
strcat(newLine, "\0");
fputs(newLine ,usernamesPasswords);
strcpy(newLine, "");
}
fclose(usernamesPasswords);
printf("\nDo you want to display the new file? Enter (y) to view and any other key to exit\n");
char word;
scanf("%c",&word);
if (word == 'y') {
readUsernamesPasswords = fopen("usernamesPasswords.txt", "r");
if (readUsernamesPasswords == NULL) {
printf("Cannot open file \n");
exit(0);
}
char r;
while((r=fgetc(readUsernamesPasswords))!=EOF) {
printf("%c", r);
}
fclose(readUsernamesPasswords);
}
return 0;
}
Expected Output:
Moodie 123456
Intelllligent password
Happee 12345678
Mischeivous qwerty
SweetKristy 123456789
KristyHoney 12345
BubblySnowflake 1234
AngelicPrincessKristy 111111
FairyPrincessKristy 1234567
BabyKristyButterfly dragon
daffyusers 123123
magpiedoodle baseball
aspiringthreat abc123
landmarksspreader football
cavaliervanquish monkey
chatteringparma letmein
veggiehydrogen 696969
teethunsure shadow
rumpboast master
lidarstrudel 666666
Instead...
123456
password
12345678
qwerty
123456789
12345
1234ke
111111incessKristy
1234567sKristy
dragonutterfly
123123
baseball
abc123
footballer
monkeysh
letmein
696969
shadow
master
666666
This only happens when I try to output on terminal.
The actual usernamesPasswords.txt file comes out as expected.
The left side of strings only seem to get printed only when I newline in place of whitespace...
I even tried fgets and fread but similar output. I have read other posts about eating or consuming so I tried using fgets or fread as suggested and even tried unget. did not seem to work. I have been looking all over stack overflow to no avail.
If this is a duplicate, I apologize in advanced. I have really tried to look all over the web for couple hours before deciding to post.
I usually don't post cuz stack overflow usually has everything already...
Please help! Thank you!
You cannot call strcat or strlen on uninitialized storage. It's Undefined Behaviour. String functions generally require input string arguments to be correctly NUL-terminated. (Without the terminator, there is no way to tell where the string ends.)
And strcat(s, "\0") is a no-op because the second argument is effectively an empty (zero-length) string. (And, as above, if s is not already NUL-terminated, it is Undefined Behaviour.)
In your program, this part of code is having few problems:
char newLine[1024];
for (w=0;w<20;w++) {
strcat(newLine, user[w]);
int q = strlen(newLine);
for (k=0;k<(25-q);k++) {
strcat(newLine, " ");
}
strcat(newLine, pass[w]);
strcat(newLine, "\n");
strcat(newLine, "\0");
fputs(newLine ,usernamesPasswords);
strcpy(newLine, "");
}
Problems like newLine buffer is not initialized and used in strcat. Concatenating empty string has no effect - strcat(newLine, "\0");. You can solve these problems by simply initializing buffer with {0} and instead of concatenating an empty string, assign \0 at appropriate buffer index. But you don't need to do all this strcat's, instead you can simply do all this in just one line like this:
char newLine[1024];
for (w=0;w<20;w++) {
snprintf (newLine, 1024, "%-25s%s\n", user[w], pass[w]);
fputs(newLine ,usernamesPasswords);
}
snprintf appends a terminating null character after the content written to the buffer.
Few points:
- You should check the return value of fopen.
- The return type of fgetc is int and not char and you are taking its return value in a char type.
- You need to take care of few things in your program like your program works on an assumption that usernames.txt and passwords.txt contains exact 20 lines. It's better to make it flexible.
Related
I need read a string and finish it. For example:
INPUT
fxy yxf
abc bac
weq qew
abg bga
acd adc
abt bta
poeq eopq
qwte wtqe
I want to finish the program after the word "wtqe".
Here is my code:
int main(){
do {
scanf("%s %s", &str1, &str2);
}while(scanf("%c") != EOF);
return 0;
}
Use fgets to read a line and sscanf to parse the two strings. If a blank line is entered or a line with only one string, the while loop will exit.
#include <stdio.h>
int main (void) {
char line[999] = "";
char str1[100] = "";
char str2[100] = "";
int result = 0;
do {
if ( fgets ( line, sizeof line, stdin)) {
result = sscanf ( line, "%99s%99s", str1, str2);
}
else {//fgets failed
break;
}
} while ( line[0] != '\n' && result == 2);
return 0;
}
The end of the loop is while(scanf("%c") != EOF)
This means that the loop quits when you reach end-of-file.
If you put all of those in a text file, and ran your program with that file as standard input (./prog < file), then it will quit after it finishes reading the file.
If you want to type all of those in, you need to indicate end-of-file to the terminal. On Linux, Mac, and similar systems, you do this with ctrl+d; on Windows I think it's ctrl-z.
Edit to add: This will give strange results if the very start of the input doesn't match. A better option might be
while (scanf("%s %s", &str1, &str2) == 2) {
// Do stuff
}
As shown by user3121023's answer, this can also cause buffer overflow issues, and you should give an explicit size to %s.
I want to create a program that opens and writes to 3 different text files, the names a user inputs.
The condition would be that if last names end with certain characters, they would be saved to a specific text file.
For example, if the user inputs a last name that ends with ian it should be saved to the ARMENIA.TXT folder.
Here is my code and the issues I encounter with it:
struct names {
char firstName[20];
char lastName[30];
} person;
int main() {
FILE *arm, *ita, *esp;
char ian[] = "ian";
char ini[] = "ini";
char ez[] = "ez";
char response;
char *ret;
arm = fopen("C:\\Programming\\ARMENIA.TXT", "wt");
ita = fopen("C:\\Programming\\ITALIA.TXT", "wt");
esp = fopen("C:\\Programming\\ESPANIA.TXT", "wt");
if (arm, ita, esp == NULL) {
printf("Error: The archives could not be created.");
return 1;
} else {
printf("Operation Successful: Archives created.\n\n");
}
do {
fflush(stdin);
printf("\n\nPlease input your first name: ");
scanf("%s", &person.firstName);
printf("Please input your last name: ");
scanf("%s", &person.lastName);
if (ret = strstr(person.lastName, ian)) {
fwrite(person.lastName, 1, strlen(person.lastName), arm);
fwrite(person.firstName, 1, strlen(person.firstName), arm);
}
if (ret = strstr(person.lastName, ini)) {
fwrite(person.lastName, 1, strlen(person.lastName), ini);
fwrite(person.firstName, 1, strlen(person.firstName), ini);
}
if (ret = strstr(person.lastName, ez)) {
fwrite(person.lastName, 1, strlen(person.lastName), ez);
fwrite(person.firstName, 1, strlen(person.firstName), ez);
}
printf("\n\nWould you like to enter another person into the archive?: (y) or (n): ");
scanf(" %c", &response);
} while (response == 'y');
printf("\n\nThe operation has finished.\n\n");
fclose(arm);
fclose(ita);
fclose(esp);
return 0;
}
Issue: Will save to folder if last name contains ian (or ini / ez) in ANY part of the last name. How do I make the condition only if it ENDS with these strings?
Issue: Will crash if last name contains ini or ez -- basically, only first If statement works.
Issue: Needs to be saved as Lastname, Firstname -- For now, it saves as LastnameFirstname.
Your program has multiple issues.
Some of the have been addressed by Ray and Stephen Lechner, but here are some more:
The reason for the crashes is you pass string to fwrite instead of FILE* stream pointers: fwrite(person.lastName, 1, strlen(person.lastName), ini); should be written:
fwrite(person.lastName, 1, strlen(person.lastName), ita);
This is an indication that you compile without proper warnings enabled. Let the compiler help avoid such silly mistakes with -Wall for gcc or /W3 for msvc.
Note also that you should use fprintf to properly format the output to your text files. For example:
if (strEndsWith(person.lastName, "ian")) {
fprintf(arm, "%s, %s\n", person.lastName, person.firstName);
}
Here is an improved version:
#include <stdio.h>
#include <string.h>
int strEndsWith(const char *str, const char *ending) {
size_t len1 = strlen(str);
size_t len2 = strlen(ending);
return len1 >= len2 && !strcmp(str + len1 - len2, ending);
}
int main(void) {
FILE *arm = fopen("C:\\Programming\\ARMENIA.TXT", "wt");
FILE *ita = fopen("C:\\Programming\\ITALIA.TXT", "wt");
FILE *esp = fopen("C:\\Programming\\ESPANIA.TXT", "wt");
if (arm == NULL || ita == NULL || esp == NULL) {
printf("Error: The archives could not be created.\n");
return 1;
} else {
printf("Operation Successful: Archives created.\n\n");
}
for (;;) {
char firstName[20];
char lastName[30];
char response;
printf("\n\nPlease input the first name: ");
if (scanf("%19s", firstName) != 1)
break;
printf("Please input the last name: ");
if (scanf("%29s", lastName) != 1)
break;
if (strEndsWith(lastName, "ian")) {
fprintf(arm, "%s, %s\n", lastName, firstName);
}
if (strEndsWith(lastName, "ini")) {
fprintf(ita, "%s, %s\n", lastName, firstName);
}
if (strEndsWith(lastName, "ez")) {
fprintf(esp, "%s, %s\n", lastName, firstName);
}
printf("\n\nWould you like to enter another person into the archive?: (y) or (n): ");
if (scanf(" %c", &response) != 1 || response != 'y')
break;
}
printf("\n\nThe operation has finished.\n\n");
fclose(arm);
fclose(ita);
fclose(esp);
return 0;
}
In addition to the issues Ray pointed out, see the following simple code for a strEndsWith-function. Hope it helps.
int strEndsWith(const char* str, const char* ending) {
size_t strlenStr = strlen(str);
size_t strlenEnding = strlen(ending);
if (strlenStr < strlenEnding)
return 0;
const char* strAtEnding = str + strlenStr - strlenEnding;
return (strcmp(strAtEnding, ending) == 0);
}
There are a number of unrelated issues here.
arm = fopen("C:\\Programming\\ARMENIA.TXT", "wt");
That should be "w+", not "wt". Same for the others. Or just "w", unless you want to both read and write.
if (arm, ita, esp == NULL)
The comma operator evaluates its left operand and discards it, then evaluates its right operand and keeps that value. So this is equivalent to if (esp == NULL)
fflush(stdin);
This is meaningless. When printing, the system is allowed to buffer output and then print it all at once, which can speed things up. fflush forces it to actually print anything that's currently in the buffer. It's useful if, for example, you want to prompt the user for input and need to make sure the prompt shows up.
As such, it only works on an output stream. (This error is actually taught in some terrible references, so I suspect this one isn't your fault. You should stop using whatever reference told you to do this.)
Addendum: As Olaf points out in the comments, this invokes undefined behavior, which is a topic unto itself. The short and imprecise version is that any undefined behavior creates bugs that are really hard to track down.
if (ret = strstr(person.lastName, ian))
This tells you that ian is in person.lastName somewhere, but not that it's at the end. For example, suppose the last name is "ian in ez". It'll match all three of your conditions. As an aside, you don't need to store ian in a variable; you can just do strstr(person.lastName, "ian").
I'm a beginner programmer trying to learn C. Currently I'm taking a class and had a project assigned which I managed to finish pretty quickly, at least the main part of it. I had some trouble coding around the main() if functions though, because I started using some new functions (that is, fgets and strncmp). Now, my code works in my compiler, but not in any of the online compilers. So I'm wondering if I did something wrong with it, or if there is any way I can improve it.
Any help or contribution is appreciated, thanks!
Below is the code, the encrypt and decrypt functions are the first two functions before the main, where I believe most of the messy shortcut-code might be.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * Encrypt(char sentence[])
{
int primes[12] = {1,2,3,5,7,11,13,17,19,23,29,31};
int x = 0;
int counter = 0;
int ispositive = 1;
while(sentence[x] != 0)
{
if (counter == 0)
{
ispositive = 1;
}
else if(counter == 11)
{
ispositive = 0;
}
if (ispositive == 1)
{
sentence[x] = sentence[x] + primes[counter];
counter++;
}
else if (ispositive == 0)
{
sentence[x] = sentence[x] + primes[counter];
counter--;
}
x++;
}
return sentence;
}
char * Decrypt(char sentence[])
{
int primes[12] = {1,2,3,5,7,11,13,17,19,23,29,31};
int x = 0;
int counter = 0;
int ispositive = 1;
while(sentence[x] != 0)
{
if (counter == 0)
{
ispositive = 1;
}
else if(counter == 11)
{
ispositive = 0;
}
if (ispositive == 1)
{
sentence[x] = sentence[x] - primes[counter];
counter++;
}
else if (ispositive == 0)
{
sentence[x] = sentence[x] - primes[counter];
counter--;
}
x++;
}
return sentence;
}
int main()
{
char message[100];
char input[7];
char *p;
int c;
int condition = 1;
while(condition == 1)
{
printf("Would you like to Encrypt or Decrypt a message? (Type TurnOff to end the program) \n \n");
fgets(input,7, stdin);
fflush(stdin);
if (!strncmp(input,"Encrypt",strlen(input)))
{
printf("\n \n Enter the message you want to Encrypt below: \n \n");
fgets(message, 100, stdin);
Encrypt(message);
printf("\n Your encrypted message is: ");
printf("%s", message);
fflush(stdin);
printf("\n \n");
}
else if (!strncmp(input,"Decrypt",strlen(input)))
{
printf("\n \n Enter the message you want to Decrypt below: \n \n");
fgets(message, 100, stdin);
Decrypt(message);
printf("\n Your Decrypted message is: ");
printf("%s", message);
fflush(stdin);
printf("\n \n");
}
else if (!strncmp(input,"TurnOff",strlen(input)))
{
printf("\n \n Thank you for using the program! \n \n");
condition = 0;
}
else
{
printf("That's not a valid input \n \n");
}
}
}
After the printf you doing fflush(stdin) instead of you have to do fflush(stdout). Because you are printing the output. The output is printed in stdout. So, you have to flush the stdout buffer not stdin buffer.
You can use the strcmp instead of strncmp. Because in here you are comparing the hole character in the input array. So, the strcmp is enough.
strcmp(input, "Encrypt").
The strcmp or strncmp function get the input in array upto a null or the size of the string you are declared.
The size for the input array is too few.
lets take the input is like below.
Encrypt\n
sureshkumar\n
In here you first fgets in main function reads the upto "Encrypt" it does not skip the '\n'.
The '\n' is readed form another fgets. So, it does not get the encrypt message "sureshkumar".
So, you have to modify you code. You will increase the size for the input array.
And check the condition like below.
if(strcmp(input, "Encrypt\n") == 0)
{
/*
You will do what you want
*/
}
You can use the above way or you can read the input and overwrite the '\n' to '\0' in the input array and compare as it is you before done. But you have to use the strcmp. Because the array size is incremented.
This is the right way for using the fgets. Use of fgets is to read upto new line.
You have to use the null character for the character array. Because this is necessary for the character arrays.
Your initiative towards using strcmp() and fgets() is good, though, it requires following understanding:
1. fgets() writes atmost size-1 characters into buffer and then terminates with '\0'. In your case,
fgets(input,7, stdin);
You gave input "Encrypt"/"Decrypt"/"TurnOff"
but
'input' buffer got data as "Encryp"/"Decryp"/"TurnOf"
because of size=7 (only (7-1)=6 characters being read, last position reserved for '\0' character by fgets()).
Your strncmp() calls will work correctly with your current code, since for strncmp(), length to compare
n = strlen(input) = 6;
6 characters are matching fine in all three cases of "Encrypt"/"Decrypt"/"TurnOff".
Summary is that your current code will work fine, But your actual intention is violated. You actually wanted to read and compare full length of option string.
EDIT DONE : Modifications suggested:
#define SIZE 9 <-- EDIT : Change done here, instead of 7, size = 9 is used
to allow reading '\n' so that it does not affect
fgets() read in successive iteration
char input[SIZE];
fgets(input, SIZE, stdin); // read str is e.g. "Encrypt\n"
input[SIZE-2] = '\0'; // To replace '\n' with '\0'
Similarly, you need to be careful when reading into 'message' array using fgets().
The input text file has some numbers per line, numbers are split by space. The first two lines only got one number, and the following lines got three. What I want to do is read each line of the input and store these numbers.
This is what I've got so far:
int
main(int argc, char *argv[]) {
int n = 0;
char buff[MAX_STRING_LEN]; //MAX_STRING_LEN is defined as 64
while (fgets(buff,MAX_STRING_LEN, stdin) != NULL) {
char temp;
if (n == 0) {
sscanf(buff, "%s", &temp);
int h_num = (int)temp;
} else if (n == 1) {
sscanf(buff, "%s", &temp);
int s_num = (int)temp;
} else {
sscanf(buff, "%s", &temp);
char *token;
token = strtok(&temp, " ");
int i = 0;
int a,b,c;
while (token != NULL) {
if (i == 0) {
a = (int)token;
token = strtok(NULL, " ");
} else if (i == 1) {
b = (int)token;
token = strtok(NULL, " ");
} else {
c = (int)token;
token = strtok(NULL, " ");
}
i++;
}
}
n++;
}
return 0;
}
The print statement I used to test my code is like:
printf("%d\n",h_num);
printf("%d\n%d\n%d\n",a,b,c);
I created a text file like this:
23
34
4 76 91
but the output is not what I expected, it's the address of the pointer I think. (I'm stuck with pointer again =( )
Could someone help me to point out what the problem is? Appreciate it.
In your code, I can see,
int h_num = (int)temp;
and
int s_num = (int)temp;
No, that is not how you convert an aphanumeric string to int.
You need to use strtol() for this purpose.
Then,
sscanf(buff, "%s", &temp);
is wrong. temp is a char, you got to use %c for that.
My suggestion for a better approach:
Read a complete line from file using fgets()
tokenize the input using strtok(), using space () as delimiter, then convert the token (if not NULL) to int using strtol()
continue untill the returned token is NULL
In this case, your code will be much more generic, as don't need to bother seperately about the number of ints present in each line.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int individualAverage(int data[][20],int j)
{
int k,average=0;
for(k=0;k<10;k++)
{
average += data[k][j];
}
return average;
}
int main()
{
int var,indAvg=0;
int i=0,j,k;
char *experiments[20];
int data[10][20];
char str[100],str2[100];
char *ptr, *token;
int no_line=1;
while(fgets(str,100,stdin) != NULL && (strcmp(str,"*** END ***") && strcmp(str,"*** END ***\n")))
{
if(no_line % 2 == 0)
{
k=0;
token = strtok (str," ");
while (token != NULL)
{
sscanf (token, "%d", &var);
data[k++][i] = var;
token = strtok (NULL," ");
}
i++;
}
else
{
ptr = strdup(str);
experiments[i] = ptr;
}
no_line++;
}
fgets(str,100,stdin);
token = strtok(str," ");
while(token != NULL && (strcmp(token,"4") && strcmp(token,"4")))
{
sscanf (token, "%d", &var);
printf("DATA SET ANALYSIS\n1.\tShow all the data\n2.\tCalculate the average for an experiment\n3.\tCalculate the average across all experiments\n4.\tQuit\nSelection: %d\n\n",var);
switch(var)
{
case 1 :
for(j=0;j<i;j++)
{
printf("%s",experiments[j]);
for(k=0;k<10;k++)
{
printf("%d ",data[k][j]);
}
printf("\n");
}
printf("\n");
break;
case 2 :
printf("What experiment would you like to use?\n");
token = strtok (NULL," ");
sscanf (token, "%s", &str);
for(j=0;j<i;j++)
{
if(strcmp(experiments[j],str) == 0)
{
indAvg = individualAverage(data,j);
printf("Experiment: %s",experiments[j]);
printf("The individual average of the experiment is %d\n",indAvg);
break;
}
}
}
token = strtok(NULL," ");
}
}
OK, so I have a method that takes lines of redirection input. The lines come in pairs. First line is the name of an experiment, and the second line has the 10 values separated by spaces for that experiment. After these pairs, there is an ending line "*** END ***"
After this line, there is one last line holding the instructions of what to do with the data.
I'm currently having a problem where I've used fgets() to store the strings of the first pairs of lines into a variable which I declared as char *experiments[20];
Each of strings that this array is pointing to will have '\n' at the end of the string because of fgets()
Back to the last line of instructions. You have values 1-4. Right now I'm looking at instruction 2. It tells the average of an experiment. So after 2 on the last line, there must be the name of one of the experiments. I've used:
char str[100];
int var;
char *token;
token = strtok(str, " ");
sscanf (token, "%d", &var);
to get the first value on the line into var (pretend it's 2). So after that would be a string. Say it's Test 1, I'll use
token = strtok (NULL," ");
sscanf (token, "%s", &str);
to get the value into str, and then I'll compare it to experiments for all possible indexes.
HOWEVER, because fgets() gives '\n' at the end of the lines, all of the experiments strings will have '\n' at the end while str will just have the name of the experiment WITHOUT '\n' therefore they will never be equal even if '\n' is the only difference between the strings.
Any solutions?
Since you know that there may be a \n at the end of the string, you could check for it, and remove it if it's there:
size_t len = strlen(str);
if (len != 0 && str[len-1] == '\n') {
str[len-1] = '\0';
}
This would terminate the line at \n, so your strcmp would succeed. An alternative is to use strncmp, and pass the length of the target string. This runs the risk of false positives when there's a longer suffix that \n, though.
You could also read your data like this:
fscanf(f, "%99[^\n]", str);
You can make your own version of fgets that doesn't store the new-line character when it encounters one, and call it myfgets. Something like this would replicate fgets's behaviour, I think, produced with respect to the description given in MSDN:
char * myfgets( char * str, int n, FILE * stream ) {
if ( n <= 0 ) return NULL; // won't accept less than or equal to zero length
int currentPos = 0;
while ( n-- > 0 ) {
int currentChar = fgetc( stream );
if ( currentChar == EOF ) return NULL;
if ( currentChar == '\n' ) break;
// if these two lines were in reversed order,
// it would behave same as the original fgets
str[currentPos++] = currentChar;
}
return str;
}
But of course the other solution is simpler, hehe...