memory overwrite when reading strings in c - c

The code I am working on needs a vector of doubles as an input and I was trying to make it variable sized, by using this small library I found on git. A first iteration using strings instead of doubles is:
printf("Write vector components (type 'stop' to stop): \n");
int stop = 0;
while (!stop)
{
fgets(c, sizeof(c), stdin);
if (strcmp("stop\n",c)!=0)
{
vector_add(&v, c);
} else {
stop = 1;
}
}
However, when I print the result (for example with 3 inputs and "stop") I get
the vector is:
stop
stop
stop
I have tried to write the first component everytime I input a new one, and the result is that the last one overwrites the first (and by extension, given the final result, every component).
However, this doesn't happen if I use vector_add manually. For example I have tried combining the example from git and my own code and the complete output is:
emil
hannes
lydia
olle
erik
stop
stop
stop
stop
So it only overwrites when reading. I can't even begin to comprehend what is happening. Haven't written any C in 2 years and I'm starting all over again.
Full code (not including vector library):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vector.c"
void main(int argc, char* argv[]) {
char c[20];
vector v; vector_init(&v);
printf("Write vector components (type 'stop' to stop):\n");
int stop = 0;
while (!stop)
{
fgets(c, sizeof(c), stdin);
if (strcmp("stop\n",c)!=0)
{
vector_add(&v, c);
// printf("%s\n", (char*)vector_get(&v, 0));
} else {
stop = 1;
}
}
printf("The vector is:\n");
for (int i = 0; i < vector_count(&v); i++) {
printf("%s\n", (char*)vector_get(&v, i));
}
} /* main */

vector_add doesn't copy the data, so your string is still stored in the variable c. When you read a new string, it overwrites the old one.
If your string library contains strdup, you can try this:
vector_add(&v, strdup(c));

Related

What is wrong with my for loop and my strcmp?

Right now, the purpose of the code is to take a user input and compare it to a text file (all in code blocks or C programming). The text file reads as:
Leia 12345
Darth 23456
R2D2 34567
Solo 45678
Jabba 56789
Yoda 67890
The code was able to combine the two strings together, but it wont recognize a correct answer nor will the for loop end after 3 tries like it's supposed to. I believe there is something wrong with my for loop, the reading of the text file, and the string comparison. And I have no idea how to fix it.
#include <stdio.h> /* for printf(), scanf() */
#include <stdlib.h> /* for system() */
#include <string.h>
#include <limits.h>
#include <ctype.h>
#include <math.h>
int main()
{
char name[5];
char pin[6];
FILE *file;
file = fopen("ident.txt", "r"); /*How to open, read, and print a text file */
char name2[11];
int i;
int c;
c = getc(file);
fgets(name2, sizeof(name2), file);
if (file == NULL)
{
printf("Error: could not open file %s", file);
return 1;
}
while (c != EOF)
{
printf("\n\tEnter your name: ");
scanf("%s", name); /*How to convert a user input into strings*/
printf("\n\tEnter your pin number: ");
scanf("%s", pin); /*How to convert a user input into strings*/
strcat(strcat(name, " "), pin); /*How to combine two user input string into one*/
printf("\n\n Entry: %s \n\n", name);
for (i = 0; i = 3; i++)
{
if (strcmp(name2, name) == 0)
{
printf("It's a Match");
}
else
{
printf("Invalid Entry. Try Again. \n");
break;
}
}
fclose(file);
}
return 0;
}
A couple of point that may help you:
It is not completely clear from your questrion what the goal of the program is - but if you're struggling it may be a good idea to try and solve a smaller version of the problem. Try making a smaller file with just one word of text, then prompt the user for input that will be compared against that single word.
You call getc(file) and fgets(name2, sizeof(name2), file) to read from the file before you check whether it has been oppen successfully - this should happen afterwards.
You generally don't check the string bouds when writing to them (and they are very small). If a user inputs a string that is longer than what the array fits, an overflow could happend and lead to unpredictable bugs. Try replacing scanf() with fgets() or a different function that lets you determine how many characters you will read.
Your for loop looks like this: (i = 0; i = 3; i++). Here's what it does:
Once, when entering the loop, set the variable i to 0.
Every time the code inside the loop is executed increase i by one.
Before re-entering the loop, set i to 3. If i is 0, exit the loop.
What you probably want is (i = 0; i < 3; i++)
Every run of the loop will do the same thing - comparing name2 to name. If you want to do something else, you should probably keep reading from the file and prompting the user for input inside the loop.
The while (c != EOF) loop will never end once entered, if you do not modify the content of c inside the loop.
From my comments:
In for (i = 0; i = 3; i++), the conditional expression is i = 3; which is actually an assignment operator and not a comparison operator. This will loop infinitely. Did you mean (e.g.) for (i = 0; i < 3; i++)? But, why have the for loop at all?
You only read one line from the text file and then loop on the user prompt/input. I think you want to restructure so that after prompting the user for and getting the name and pin, it is then that you want to loop through all lines of the file to look for a match. But, you'd have to reread the file on each failed user attempt [or store the data in a dynamically allocated array]
When you read a line from the file, you use fgets and get the whole line, including the trailing newline character [which you should strip (e.g.) name2[strcspn(name2,"\n")] = 0. When you prompt the user you're using scanf to get the name and pin separately. Combining with strcat to get a whole line isn't the best way. You could take file input the same way as you do user input and do two strcmp, one for name and the other for pin
You are doing break on your else but you probably want it on your if (i.e. you want to stop when there is a match and not a mismatch).
The easiest way to fix this is to put the file read and comparison into a function. Then, main can loop on the user prompt/input and call the function to do the matching.
Additionally, if the input file can not be opened, the program is printing an error message but trying to print file (a FILE *) with "%s" instead of the file's name (e.g. ident.txt)
Unfortunately, I had to do a lot of restructuring to get the code to work. There were just so many issues that it's difficult to list them all.
But, here is the refactored and working code:
#include <stdio.h> /* for printf(), scanf() */
#include <stdlib.h> /* for system() */
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include <math.h>
// findmatch -- find match for user name/id in file
int
findmatch(const char *name)
{
FILE *xfin;
const char *filename = "ident.txt";
char buf[100];
int match = 0;
xfin = fopen(filename, "r");
if (xfin == NULL) {
printf("Error: could not open file %s -- %s\n",
filename,strerror(errno));
exit(1);
}
while (fgets(buf,sizeof(buf),xfin) != NULL) {
// strip newline
buf[strcspn(buf,"\n")] = 0;
// match "name pid"
if (strcmp(buf,name) == 0) {
match = 1;
break;
}
}
fclose(xfin);
return match;
}
int
main(void)
{
int i;
int match;
char name[100];
char pin[100];
// do only so many tries before kicking out user
for (i = 0; i < 3; i++) {
printf("\n\tEnter your name: ");
scanf("%s", name);
printf("\n\tEnter your pin number: ");
scanf("%s", pin);
/* How to combine two user input string into one */
// NOTE: there may be a cleaner way to do this, but the code will work
strcat(strcat(name, " "), pin);
printf("\n\n Entry: %s \n\n", name);
match = findmatch(name);
if (match) {
printf("It's a Match\n");
break;
}
printf("Invalid Entry. Try Again. \n");
}
if (! match) {
printf("Too many retries\n");
exit(1);
}
printf("Doing stuff ...\n");
return 0;
}

Why am I getting garbage characters in my output for Test 1 and Test3 occasionally?

I am having problems with my test cases writing garbage to my result variable. I am pretty new to C, so I am having trouble determining what is causing it.
//Author: Ryan Fehr
//Contributors:
#include <stdio.h>
#include <string.h>
int remover(char[], char[], char[]);
int remover(char source[], char substring[], char result[])
{
char *current = source;
// printf("%s n", current);
char *currentSub = substring;
//printf("%c n", *currentSub);
int i = 0;
while(*current != '\0')//Loops through the source string
{
//Uncommenting the line below will show you the comparisons being performed
printf(" %c | %c \n", *current, *currentSub);
if(*current == *currentSub || *currentSub == '\0')//True when a letter matches with a letter in the subStr or the complete subStr was found
{
if(*currentSub == '\0')
{
char pre[((current-(i) - source))];//Stores everything before the subString in pre(current-i) - source
memcpy(pre, source, (current-i) - source);
printf("Pre: %s\n",pre);
//Counts how many chars are after the substring
int n = 0;
while(*current != '\0')
{
n++;
current++;
}
char post[n];//Stores everything after the subString in post
memcpy(post, current-n, n);
printf("Post: %s\n",post);
strcat(result, pre);
strcat(result,post);
printf("Substring removed: %s\n", result);//Prints the value after substring has been removed
return 1;
}
i++;
currentSub++;
}
else
{
i=0;
currentSub = substring;
}
current++;
}
return 0;
}
int main(void)
{
//TEST 1
char s[] = "jump_on_down_to_getfart_and_up_to_get_down_";
char sub[] = "fart";
char r[100] = "";
printf("Test 1:\n");
printf("Source: %snSubstring: %s\n",s,sub);
printf("%d\n\n", remover(s, sub, r));
//EXPECTED OUTPUT: 1
//TEST 2
strcpy(s, "racecar");
strcpy(sub, "x");
strcpy(r, "");
printf("Test 2:n");
printf("Source: %snSubstring: %s\n",s,sub);
printf("%d\n\n", remover(s, sub, r));
//EXPECTED OUTPUT: 0
//TEST 3
strcpy(s, "jump on down to get and up to get down ");
strcpy(sub, "up");
strcpy(r, "");
printf("Test 3:n");
printf("Source: %snSubstring: %s\n",s,sub);
printf("%d\n\n", remover(s, sub, r));
//EXPECTED OUTPUT: 1
}
Here is a screen shot of the output for Test1, as you can see I am getting extra garbage printing and I think my math is correct for my substrings, so I am not sure what is causing this.
I can't embed images so it is linked
Nested functions are not a part of standard C. Only GCC (and maybe Clang emulating, or in compatibility mode with, GCC) support it. Do not post nested functions on Stack Overflow (or Code Review) if you want to get away without scathing comments being passed on the unsuitability of nested functions.
Your problem is that your variable r in main is an array of size 1, but you use it in the remover() function as if it was bigger. You get undefined behaviour as a result.
At minimum, you should use:
char r[100]; // Or any other convenient size - for the test data 50 would do
There may be other problems; I've not compiled the code (I decline to compile C code with nested functions; it won't pass my default compilation options).
Do not insert one function inside another function.
The posted code has the remover() function nested inside the main() function.
While some compilers will allow that as an 'extension', (gcc comes to mind ) you should never nest functions.
For ease of readability and understanding: 1) consistently indent the code. indent after every opening brace '{'. unindent before every closing brace '}. Suggest using 4 spaces for each indent level. 2) separate code blocks (for, if, else, while, do... while, switch, case, default) via a blank line

Reading a text file in C, stopping at multiple points, breaking it into sections

I have a program that has a text file that is variable in length. It must be capable of being printed in the terminal. My problem is that if the code is too large, part of it becomes inaccessible due to the limited scroll of terminal. I was thinking of having a command executed by a character to continue the lines after a certain point, allowing the user to see what they needed, and scroll if they needed. However the closest I have come is what you see here, which prints the text file one line at a time as you press enter. This is extremely slow and cumbersome. Is there another solution?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
FILE *audit;
audit = fopen("checkout_audit.txt", "r");
char length_of_code[60000];
int ch;
while ((ch = fgetc(audit)) != EOF)
{
fgets(length_of_code, sizeof length_of_code, audit);
fprintf(stdout, length_of_code, audit);
getch();
if (ferror(audit))
{
printf("This is an error message!");
return 13;
}
}
fclose(audit);
return 0;
}
The libraries are included as I tried various methods. Perhaps there is something obvious I am missing, however after looking around I found nothing that suited my needs in C.
You can keep a count of something like num_of_lines and keep incrementing it and when it reaches some number(say 20 lines) then do a getchar() instead of doing it for each line.
Make sure you don't use feof() as already suggested. Just for the purpose of how it can be done I am showing the below snippet.
int num_of_lines = 0;
while(!feof(fp))
{
// fgets();
num_of_lines++;
if(num_of_lines == 20)
{
num_of_lines = 0;
getch();
}
}
Putting the same thing in your code:
int main()
{
FILE *audit;
audit = fopen("checkout_audit.txt", "r");
char length_of_code[60000];
int num_of_lines = 0;
int ch;
while (fgets(length_of_code, sizeof length_of_code, audit) != NULL)
{
fprintf(stdout, length_of_code, audit);
if (ferror(audit))
{
printf("This is an error message!");
return 13;
}
num_of_lines++;
if(num_of_lines == 20)
{
num_of_lines = 0;
getch();
}
}
fclose(audit);
return 0;
}
From the man page of fgets()
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s.
Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte is stored after the last character in the buffer.
So char length_of_code[60000]; is not a better option.
Try to set the size of array to optimum value which in most case is 80.
Also as fgets fetches line by line you will have to output line by line untill EOF
EDIT:
1. 2nd argument to fprintf should be the format specifier and not length
2. 3rd arg should be a string and not the file pointer
fprintf(stdout, "%s", length_of_code);
Code Snippet:
while (fgets(length_of_code, sizeof(length_of_code), audit))
{
fprintf(stdout, "%s", length_of_code);
getch();
if (ferror(audit))
{
printf("This is an error message!");
return 13;
}
}

Problems with atoi() exercise

I'm having problems with this simple loop exercise. I think the code is correct and I don't get any errors however when I run the program, I just get "^C" over and over again. Please help.
#import <readline/readline.h>
#import <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[])
{
printf("Where should I start counting? ");
const char *numInput = readline(NULL);
int countDownStart = atoi(numInput);
for (int i = countDownStart; i >= 0; i--) {
if (i % 3 == 0){
printf("%d\n", i);
if (i % 5 == 0) {
printf("Found one!\n");
}
}
}
return 0;
}
UPDATE 8/3/14
The code works when I enter the starting number using the numbers above my keyboard. However when I enter the starting number with my 10 key, I get "^C" every time I hit enter. Now I'm completely flummoxed but at least my code works.
Thank you for the help everyone. I understand atoi is not the best function to use but am trying to work through the Big Nerd Objective-C book.
Use strtol inplace of atoi as it returns error value in case of conversion failures.
You have to check the output received from function readline
const char *numInput = readline(NULL);
printf ("Input %s", numInput); //debugging
int countDownStart = atoi(numInput);
If the function is always returning the same string means, then the result also will remain the same.

Comparing 2 substrings in C

I having trouble reading a string of characters from a file and then comparing them for the first part of my homework on ubuntu using C.
So the program compiles fine but it seems I get stuck in an infinite loop when it gets to the while loop under the compare string portion of the code. Thanks.
Also, can I get some advice on how to take multiple inputs from the terminal to compare the string from the 'bar' file and the string of x substring of characters after that in the terminal. My output should look like:
% echo "aaab" > bar
% ./p05 bar aa B
2
1
%
This is what I have so far:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void /*int argc, char *argv[]*/)
{
/******* Open, Read, Close file**********/
FILE *ReadFile;
ReadFile = fopen(/*argv[1]*/"bar", "r");
if(NULL == ReadFile)
{
printf("\n file did not open \n");
return 1;
}
fseek(ReadFile, 0 , SEEK_END);
int size = ftell(ReadFile);
rewind(ReadFile);
char *content = calloc( size +1, 1);
fread(content,1,size,ReadFile);
/*fclose(ReadFile); */
printf("you made it past opening and reading file\n");
printf("your file size is %i\n",size);
/*********************************/
/******String compare and print*****/
int count =0;
const char *tmp = "Helololll";
while (content = strstr(content,"a"))
{
count++;
tmp++;
}
printf("Your count is:%i\n",count);
/***********************************/
return 0;
}
The following loop is infinite if the character 'a' occurs in content.
while (content = strstr(content, "a"))
{
count ++;
tmp ++;
}
It resets content to point to the location of the first occurrence of 'a' on the first iteration. Future iterations will not change the value of content. IOW, content points to "aaab" so the call to strstr will find the first 'a' every time. If you replace tmp++ with content++ inside of your loop, then it will be closer to what you want. I would probably write this with a for loop to make it a little more clear that you are iterating.
char const * const needle = "a";
for (char *haystack=content; haystack=strstr(haystack, needle); haystack++) {
count++;
}
The haystack is incremented so that it always decreases in size. Eventually, you will not find the needle in the haystack and the loop will terminate.

Resources