While Loop clearing my array? (C) - c

I've been hard at this problem for a bit and am wondering if anybody can find what Im doing wrong. Im reading user input from stdin, breaking up the string they input via strtok(), and storing it into an array of char *'s. The array of char *'s is defined outside of the while loop.
So: a user types in input via stdin, and an array is filled with strings with each word from the command.
The thing is, if the user simply hits enter I want the array to MAINTAIN it's value! I want the same values to stay in the array...so I can re-execute the same command. It appears that the while loop is clearing my array of char*'s instead. Here's code:
char *commands[3];
char *result = NULL;
char delims[] = " "; //a space AND a tab!
while (1) {
printf(PROMPT);
//Gathers user input!
char *input;
char stuff[230];
input = fgets(stuff, 230, stdin);
printf("input has length %i\n", strlen(input));
int helper = strlen(input);
int i = 0;
result = strtok(input, delims);
printf("helper has length %i\n", helper);
printf("commands[0] CHECK 1:%s", commands[0]);
if (helper >1)
{
while( result != NULL)
{
printf("while gets hit!\n");
if (i < 4)
{
commands[i] = result;
result = strtok(NULL, delims );
i++;
}
}
}
printf("commands[0] is CHECK 2:%s", commands[0]);
if (strncmp(commands[0], "step", 4) == 0)
{
lc3_step_one(p);
}
printf("commands[0] is CHECK 3:%s", commands[0]);
}
The printf's CHECK 1, CHECK 2,and CHECK 3 all print nothing if the user hits enter. In the case they last typed "step" I want "step" to stay in the array and thusly be executed again!

You are filling the commands array with pointers to the stuff array. That array is being overwritten by the fgets each time (probably replacing the first character with null). You would need to copy the data out to preserve it.

Related

C - Is there a way to read a single character of user input, and not have the rest "pushed down" to the next request for input?

So, I'm working on a simple hangman game in C, and I have the function read_guess, shown below.
void read_guess(char *guesses, char *p_current_guess)
{
int valid_guess = 0;
// Repeatedly takes input until guess is valid
while (valid_guess == 0)
{
printf(">>> ");
fgets(p_current_guess, 2, stdin);
if (!isalpha(*p_current_guess)) printf("Guesses must be alphabetic. Please try again.\n\n");
else
{
valid_guess = 1;
// Iterates over array of guesses and checks if letter has already been guessed
for (int i = 0; guesses[i] != '\0'; i++)
{
if (guesses[i] == *p_current_guess)
{
printf("You have already guessed this letter. Please try again.\n\n");
valid_guess = 0;
break;
}
}
}
}
}
I've tried all the standard input functions (including getchar), but with all of them, when an input larger than one character is supplied, instead of taking just the first character and moving on (or asking again), the rest of the input is "pushed back", and the next time input is requested, whether it be because the input contained a non-alphabetic character or the next round begins, the rest of the input is automatically processed. This repeats for each character of the input.
How can I avoid this?
You are using fgets which is good, but unfortunately not the right way...
fgets reads up to an end of line or at most 1 less the the number of character asked. And of course remaining characters are left for the next read operation...
The idiomatic way would be to ensure reading up to the end of line, whatever the length, or at least up to a much larger length.
Simple but could fail in more than SIZE characters on input:
#define SIZE 64
...
void read_guess(char *guesses, char *p_current_guess)
{
char line[SIZE];
int valid_guess = 0;
// Repeatedly takes input until guess is valid
while (valid_guess == 0)
{
printf(">>> ");
fgets(line, SiZE, stdin); // read a line of size at most SIZE-1
p_current_guess[0] = line[0]; // keep first character
p_current_guess[1] = '\0';
...
Robust but slightly more complex
/**
* Read a line and only keep the first character
*
* Syntax: char * fgetfirst(dest, fd);
*
* Parameters:
* dest: points to a buffer of size at least 2 that will recieve the
* first character followed with a null
* fd : FILE* from which to read
*
* Return value: dest if one character was successfully read, else NULL
*/
char *readfirst(dest, fd) {
#define SIZE 256 // may be adapted
char buf[SIZE];
char *cr = NULL; // return value initialized to NULL if nothing can be read
for (;;) {
if(NULL == fgets(buff, sizeof(buff), fd)) return cr; // read error or end of file
if (0 == strcspn(buff, "\n")) return cr; // end of file
if (cr == NULL) { // first read:
cr = dest; // prepare to return first char
dest[0] = buff[0];
dest[1] = 0;
}
}
}
You can then use it simply in your code:
void read_guess(char *guesses, char *p_current_guess)
{
int valid_guess = 0;
// Repeatedly takes input until guess is valid
while (valid_guess == 0)
{
printf(">>> ");
fgetfirst(p_current_guess, stdin);
You can discard all input until end-of-line, each time you want to ask for input.
void skip_to_eol(FILE* f, int c)
{
while (c != EOF && c != '\n')
c = fgetc(f);
}
...
char c = getchar(); // instead of fgets
skip_to_eol(stdin, c);
You can use getch() function on windows to get single character. and this is linux equivalent
What is the equivalent to getch() & getche() in Linux?

Problem calling a function that uses strtok() inside of a while loop

Hi i'm struggling with understanding what's wrong with my program.
My best guess is something related with this line of code here:
scanf("%s", str);
The thing is i'm trying to call a function that uses a strtok on a String passed on to it typed by the user, all of this inside of a while loop as shown in the code example below:
int i = 0;
char str[80];
while(i != 3){
printf("Type in some string so i can break it: ");
scanf("%s", str);
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
return 1;
Result (not what i want, see further below what i actually want):
Type in some string so i can break it: hey there how are you doing!
hey
Loop 0 ended.
Type in some string so i can break it:
there
Loop 1 ended.
Type in some string so i can break it:
how
Loop 2 ended.
The reason why i think this is caused by the scanf line is because the program works fine when i'm using instead some dummy pre-declared String
int i = 0;
while(i != 3){
char str[80] = "hey there how are you doing!";
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
return 1;
Result:
hey
there
how
are
you
doing!
Loop 0 ended.
hey
there
how
are
you
doing!
Loop 1 ended.
hey
there
how
are
you
doing!
Loop 2 ended.
Here's the funtion that uses strtok, most of the code here is taken from https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
int testFunc(char linha[80]){
//
const char s[2] = " ";
char *token;
/* get the first token */
token = strtok(linha, s);
/* walk through other tokens */
while(token != NULL) {
printf("%s\n", token);
token = strtok(NULL, s);
}
return 1;
}
I'm puzzled, it's like the program is executing testFunc() in paralel with the main function.
I think the problem is when you execute this loop:
while(i != 3){
printf("Type in some string so i can break it: ");
scanf("%s", str);
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
scanf gets only one word at a time, so the loop cycles 3 times, you only get 3 words no matter how long the input string is.
On the other hand, in your other example you already have a string to break apart so the function will work.
There are different ways to get spaced strings from the console but here is what I consider to be a good option to do it:
str[MAX_SIZE];
fgets(str, MAX_SIZE, stdin);
// where MAX_SIZE is the maximum size you want to allow for the string,
//must be smaller than str.
According to scanf(3) man page:
Matches a sequence of non-white-space characters; the next
pointer must be a pointer to the initial element of a
character array that is long enough to hold the input sequence
and the terminating null byte ('\0'), which is added
automatically. The input string stops at white space or at
the maximum field width, whichever occurs first
You can use fgets or fread for input:
char buffer[1000];
/* fgets (reads a line of text with trailing newline */
fgets (buffer, 1000, stdin);

compare multiple strings in single input in C

I currently have a piece of code that compares 1 input to a variable...
for example, when i input "GET" it compares it to the string i have set and then opens a file. but what if i want to compare more than one string in the input? such as if someone inputs "GET ./homepage.html"
so the first string GET indicates that they want to retrieve a file, and the second string "./homepage.html" is the file they want to view?
My thoughts on this would be to build an array with a combination of GET + all the possible file combinations and then use strcomp to choose the right one and open the specified file..? but i'm not 100% on how i would link my input to compare to a whole array?
current code is below, very basic string compare -> opens and writes file to stdout.
int main(int argc, char *argv[] ) {
MainStruct val;
parse_config(&val);
char userInput[100] = "success.txt";
char temp[100];
if (checkaccess() == 0)
{
parse_config(&val);
} else {
fprintf(stderr,"unable to load config file\n");
}
printf("Connected to Domain : %s", val.domain);
fgets(temp, 6, stdin);
temp[strcspn(temp, "\n")] = '\0';
if(strcmp(temp, "GET /") == 0 )
{
openfile(userInput);
} else {
printf("that was not a very valid command you gave\n");
}
}
EDIT: i should also mention that the second string input should also == userInput that the function openfile reads in. not sure how to separate out the two strings.
There are a couple of ways to approach this. The most straight forward is to read your full line of input into temp and then break temp into tokens with strtok or the like. The line of input would include your command (e.g. GET) and any other values you need to act upon. You can then make a decision if you received sufficient input (i.e. GET and a filename) to then respond as you intend.
Below is a short example that creates an array of char arrays (strings) to hold the tokens entered as temp. A couple of defines at the beginning limit each token to 64 chars and the maximum number of tokens to 5 (adjust as needed) It then breaks temp into tokens and checks whether the user entered more than 1 word. It then responds to GET and shows the filename it collected. (you can take whatever action you need). It also checks the number of tokens entered to make sure you don't try and write beyond the end of the array.
Take a look and let me know if you have questions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXISZ 64
#define MAXIN 5
int main (void) {
char temp[MAXISZ] = {0}; /* temp variable */
char input[MAXIN][MAXISZ] = {{0}}; /* array of strings to hold input */
size_t icnt = 0; /* number of input words */
size_t tlen = 0; /* length of temp read by fgets */
printf ("\n Enter command [filename]: ");
if (fgets (temp, MAXISZ, stdin) == NULL) {
printf ("error: fgets failed.\n");
return 1;
}
/* get length and trim newline */
tlen = strlen (temp);
while (tlen > 0 && temp[tlen - 1] == '\n')
temp[--tlen] = 0;
/* if temp contains a space */
if (strchr (temp, ' '))
{
/* break tmp into tokens and copy to input[i] */
char *p = NULL;
for (p = strtok (temp, " "); p != NULL; p = strtok (NULL, " "))
{
strcpy (input[icnt++], p);
/* check if MAXIN reached */
if (icnt == MAXIN)
{
printf ("error: MAXIN token exceeded.\n");
break;
}
}
/* if more than 1 word input, use 1st as command, next as filename */
if (icnt > 0)
{
if (strcmp (input[0], "GET") == 0)
printf ("\n You can open file : %s\n", input[1]);
}
}
else
printf ("\n Only a single word entered as command '%s'.\n", temp);
printf ("\n");
return 0;
}
Output
$ ./bin/fgets_split
Enter command [filename]: GET /path/to/myfile.txt
You can open file : /path/to/myfile.txt
or
$ ./bin/fgets_split
Enter command [filename]: GET
Only a single word entered as command 'GET'.

Displaying the contents of a dynamic array backwards

So the program is supposed to do the following:
Ask the user to enter strings (max length of the string being 250), and once the user enters nothing (so basically hitting 'enter'), the program stops taking input and proceeds to display every string the user has input backwards.
Here's my code - everything works except I can't enter the while loop at the bottom.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char userInput[250];
char *newSpace;
char *array;
int stringLength;
int inputElems = 0;
//Reset startingPtr back to where 'array' begins
char *startingPtr = array - inputElems;
// Sets endPtr to the last input element in the array
char *endPtr = startingPtr + inputElems;
do
{
puts("Please enter a string!");
// Gets input from user
fgets(userInput, 250, stdin);
// Finds out the number of characters the user entered
// + 1 to make room for the null character
stringLength = strlen(userInput) + 1;
// Allocate memory with the needed space
newSpace = malloc(stringLength);
// If malloc didn't allocate memory, display error
if (NULL == newSpace)
{
puts("Error!");
}
// Copy user input into array
strcpy(newSpace, userInput);
// Save input into array
array = newSpace;
// For testing purposes only, this line will be deleted once I can access the array
//puts("Here's what you wrote");
//printf("%s", array);
// Increase array
array++;
// Increase number of times user has input something
inputElems++;
} while(stringLength != 2);
//puts("Testing outside");
while (endPtr > startingPtr)
{
//puts("Testing inside");
--endPtr;
printf("%s", *endPtr);
}
free(newSpace);
}
Your while loop body is never executed because you never modify endPtr and startingPtr throughout the program's lifetime, they both point to the same location. Thus, endPtr > startingPtr will never be true.
Also, array++ does not work the way you expect: array points to the first character of what the user wrote, and array++ just moves it forward to the next character. I think you want an array of char *. Thus, change char *array; to char *array[250]; (assuming that the user can enter at most 250 sentences).
And of course, since you can't increment an array, because an array is not a modifiable l-value, you must also keep a count for the last index written. But I see that you already have inputElems, that should be enough. Here's the modified code:
int main()
{
char userInput[250];
char *newSpace;
char *array[250];
int stringLength;
int i;
int inputElems = 0;
do
{
puts("Please enter a string!");
// Gets input from user
fgets(userInput, 250, stdin);
// Finds out the number of characters the user entered
// + 1 to make room for the null character
stringLength = strlen(userInput) + 1;
// Allocate memory with the needed space
newSpace = malloc(stringLength);
// If malloc didn't allocate memory, display error
if (NULL == newSpace)
{
puts("Error!");
}
// Copy user input into array
strcpy(newSpace, userInput);
// Save input into array
array[inputElems] = newSpace;
// For testing purposes only, this line will be deleted once I can access the array
//puts("Here's what you wrote");
//printf("%s", array);
// Increase number of times user has input something
inputElems++;
} while(stringLength != 2);
//puts("Testing outside");
for (i = inputElems-1; i >= 0; i++)
{
//puts("Testing inside");
printf("%s", array[i]);
free(array[i]);
}
return 0;
}
Note the updated loop in the end of the code. It goes through the array from end to beginning. Note that I changed the place where you call free(). Since we're allocating memory inside a loop, for each position in array, we must also free() every position, thus this must also be made inside a loop.
Ok. you need an array of pointers like: char *arr[10];
You can store here 10 strings from arr[0] to arr[9]. (Well not directly 10 strings, but the pointers to them)
arr[0] = (char*)malloc(sizeof(char * length_of_string));
strncpy(arr[0], your_string, length_of_string);
When just print arr[9] to arr[0].
mfg

C - separating strings in the input stream

My program is supposed to be able to create new structures and store them in an array, however, the commands for storing and displaying pose difficulty.
To create a new variable struct in the array, the user inputs "set varname varcontents
To display the contents of a variable, the user inputs "set varname"
To display all variables, the user inputs "set"
I can't quite figure out how to check if there are multiple strings ("set" "varname" "varcontents") or if there is only "set"
char command[2][5] = { "set", "clear"};
printf("prompt> ");
scanf("%s",inputString);
if(strncmp(inputString,command[0],5) == 0 )
{
//code to create new struct, display structs etc...
}
else if(strncmp(inputString,command[1],5) == 0 )
{
//code to clear struct
}
Right now the if loop only passes if the user inputs "set".
I could probably take the comparison of the first few letters, and then take the full comparison and subtract the first few characters to generate the name of the new struct, but this seems too complicated, there must be an easier solution.
Any help is appreciated!
You could split the sentence into array of words and you can compare those words and run your functions.Give a try and If u want i can post the code.
There are some Problems in your code. First of all, scanf won't read "set variablename variablevalue", because it skips on whitespaces. It's not considered safe anyway, since it allows buffer overflows easily - specially beginners should rather use fgets().
But the main Problem is somewhere else - Consider the following snippet:
scanf("%s", inputString);
What would happen if you enter: 'set xyz 12'? scanf would just read 'set' and the other Input will be ignored. So there's no point in checking against the other parameters 'xyz' and '12'.
Maybe you want to use something like
scanf("%s %s %s", inputString1, inputString2, inputString3);
but I would advise against it and rather use fgets(). Apart from that you just Need simple pointer arithmetic to skip over the characters which you already processed.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (){
char* command[] = { "set", "clear"};
char input[256], varName[256], varContents[256];
char* pointer = input;
int i = 0;
printf("prompt>");
fgets(input, 255, stdin);
if(strncmp(pointer, command[0], strlen(command[0])) == 0 ){
pointer += strlen(command[0]) + 1;
while(*pointer != ' ' && *pointer != '\n'){
varName[i] = *pointer;
pointer++;
i++;
}
if(*pointer == '\n'){ printf("Not enough arguments"); return 1; }
varName[i] = '\0';
pointer++;
i = 0;
while(*pointer != ' ' && *pointer != '\n'){
varContents[i] = *pointer;
pointer++;
i++;
}
varContents[i] = '\0';
//code to create new struct, display structs etc...
printf("Set VarName: %s VarContents: %s\n", varName, varContents);
}else if(strncmp(pointer, command[1], strlen(command[1])) == 0 ){
//code to clear struct
}
return 0;
}
You are only reading one string, you should use two scanf's to read two
char arg0[30], arg1[30];
while (scanf("%s %s", arg0, arg1) < 2);
That will read until both strings are entered.
Hope this helps.

Resources