C - separating strings in the input stream - c

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.

Related

ANSI C strcmp() function never returning 0, where am I going wrong?

C isn't the language I know so I'm out of my comfort zone (learning C) and I have ran into an issue that I can't currently figure out.
I am trying to read from a text file one word at a time and compare it to a word that I have passed into the function as a pointer.
I am currently reading it from the file one character at a time and storing those characters in a new char array until it hits a space, then comparing that char array to the original word stored in the pointer (stored where it's pointing to, anyway).
When I do a printf to check if both arrays are the same they are, they both equal "Hello". At first I thought maybe it's because my char array doesn't have an end terminator but I tried adding one but still nothing is seeming to work.
My code is below and I would appreciate any help. Again C isn't my strong area.
If I do "Hello" it will be > 0 by the way, so I think it's because the gets() stdin function is also including the enter key or something of that sort. I am not sure of a better way to grab the string though.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int partA(char*);
main()
{
// Array to store my string
char myWord[81];
// myword = pointer to my char array to store. 80 = the size (maximum). stdin = standard input from my keyboard.
fgets(myWord, 80, stdin);
partA(myWord);
}
int partA(char *word)
{
// points to file.
FILE *readFile;
fopen_s(&readFile, "readThisFile.txt", "r");
char character;
char newWord[50];
int i = 0;
while ((character = fgetc(readFile)) != EOF)
{
if (character == ' ')
{
newWord[i] = '\0';
int sameWord = strcmp(word, newWord);
printf("Word: %s", word);
printf("newWord: %s", newWord);
if (sameWord == 0)
printf(" These words are the same.");
if (sameWord > 0)
printf(" sameWord > 0.");
if (sameWord < 0)
printf(" sameWord < 0.");
printf("\n");
i = 0;
}
if (character != ' ')
{
newWord[i] = character;
i++;
}
printf("%c", character);
}
fclose(readFile);
return 1;
}

How to take a user command input of varying size and put it into an array

I'm creating two programs that form a game and will be communicating with each other where one of them is essentially a user, but I'm starting off with building one and typing myself to this first program.
I want to input commands such as 'turn d1d2d3d4d5d6' (where the di are dice rolls), 'rerolled d1d2d3d4d5d6' and so forth, theres a bunch of commands. I want my program called player to take these commands and they'll do something with it.
Just to begin with I'm trying to take the input using stdin and putting it in array, then checking the array to see if its a valid command. However I can't seem to use fgetc and the array correctly. What i'm doing currently is just to take the input, put into an array and print it.
I don't actually want it to be 128 size array, I want it to be completely adjustable but I don't know how to do this with fgets. The if loop to check if its NULL is to find out if an array is empty but that's defintely wrong, not sure what to put in place there.
while(1){
int i = 1;
char* command[128];
fgets(command, 128, stdin);
for (i=0; i < 128; i++){
if (command[i] == NULL){
printf("%c\n", command[i]);
}
}
return 0;
}
So to be specific my main goal right now is take a command such as 'eliminated p' from the user and command becomes command=["eliminated","p"]
sample code:
#include <stdio.h>
#include <string.h>
int main(void) {
while(1){
char command[128];
if(NULL == fgets(command, sizeof command, stdin))//or use getline
break;
if(strchr(command, '\n') == NULL){//Too long
printf("Too long\n");
while(getchar() != '\n')
;//clear input
continue;
}
char *operation = strtok(command, " \t\n");
if(operation == NULL){
printf("Empty command\n");
continue;
}
char *operand = strtok(NULL, " \t\n");;
if(operand == NULL){
printf("Empty operand\n");
continue;
}
printf("operation:%s\noperand:%s\n", operation, operand);
char *commands[] = {operation, operand};
//do stuff
}
return 0;
}

How to extract a substring from a string in C?

I tried using strncmp but it only works if I give it a specific number of bytes I want to extract.
char line[256] = This "is" an example. //I want to extract "is"
char line[256] = This is "also" an example. // I want to extract "also"
char line[256] = This is the final "example". // I want to extract "example"
char substring[256]
How would I extract all the elements in between the ""? and put it in the variable substring?
Note: I edited this answer after I realized that as written the code would cause a problem as strtok doesn't like to operate on const char* variables. This was more an artifact of how I wrote the example than a problem with the underlying principle - but apparently it deserved a double downvote. So I fixed it.
The following works (tested on Mac OS 10.7 using gcc):
#include <stdio.h>
#include <string.h>
int main(void) {
const char* lineConst = "This \"is\" an example"; // the "input string"
char line[256]; // where we will put a copy of the input
char *subString; // the "result"
strcpy(line, lineConst);
subString = strtok(line,"\""); // find the first double quote
subString=strtok(NULL,"\""); // find the second double quote
printf("the thing in between quotes is '%s'\n", subString);
}
Here is how it works: strtok looks for "delimiters" (second argument) - in this case, the first ". Internally, it knows "how far it got", and if you call it again with NULL as the first argument (instead of a char*), it will start again from there. Thus, on the second call it returns "exactly the string between the first and second double quote". Which is what you wanted.
Warning: strtok typically replaces delimiters with '\0' as it "eats" the input. You must therefore count on your input string getting modified by this approach. If that is not acceptable you have to make a local copy first. In essence I do that in the above when I copy the string constant to a variable. It would be cleaner to do this with a call to line=malloc(strlen(lineConst)+1); and a free(line); afterwards - but if you intend to wrap this inside a function you have to consider that the return value has to remain valid after the function returns... Because strtok returns a pointer to the right place inside the string, it doesn't make a copy of the token. Passing a pointer to the space where you want the result to end up, and creating that space inside the function (with the correct size), then copying the result into it, would be the right thing to do. All this is quite subtle. Let me know if this is not clear!
if you want to do it with no library support...
void extract_between_quotes(char* s, char* dest)
{
int in_quotes = 0;
*dest = 0;
while(*s != 0)
{
if(in_quotes)
{
if(*s == '"') return;
dest[0]=*s;
dest[1]=0;
dest++;
}
else if(*s == '"') in_quotes=1;
s++;
}
}
then call it
extract_between_quotes(line, substring);
#include <string.h>
...
substring[0] = '\0';
const char *start = strchr(line, '"') + 1;
strncat(substring, start, strcspn(start, "\""));
Bounds and error checking omitted. Avoid strtok because it has side effects.
Here is a long way to do this: Assuming string to be extracted will be in quotation marks
(Fixed for error check suggested by kieth in comments below)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char input[100];
char extract[100];
int i=0,j=0,k=0,endFlag=0;
printf("Input string: ");
fgets(input,sizeof(input),stdin);
input[strlen(input)-1] = '\0';
for(i=0;i<strlen(input);i++){
if(input[i] == '"'){
j =i+1;
while(input[j]!='"'){
if(input[j] == '\0'){
endFlag++;
break;
}
extract[k] = input[j];
k++;
j++;
}
}
}
extract[k] = '\0';
if(endFlag==1){
printf("1.Your code only had one quotation mark.\n");
printf("2.So the code extracted everything after that quotation mark\n");
printf("3.To make sure buffer overflow doesn't happen in this case:\n");
printf("4.Modify the extract buffer size to be the same as input buffer size\n");
printf("\nextracted string: %s\n",extract);
}else{
printf("Extract = %s\n",extract);
}
return 0;
}
Output(1):
$ ./test
Input string: extract "this" from this string
Extract = this
Output(2):
$ ./test
Input string: Another example to extract "this gibberish" from this string
Extract = this gibberish
Output(3):(Error check suggested by Kieth)
$ ./test
Input string: are you "happy now Kieth ?
1.Your code only had one quotation mark.
2.So the code extracted everything after that quotation mark
3.To make sure buffer overflow doesn't happen in this case:
4.Modify the extract buffer size to be the same as input buffer size
extracted string: happy now Kieth ?
--------------------------------------------------------------------------------------------------------------------------------
Although not asked for it -- The following code extracts multiple words from input string as long as they are in quotation marks:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char input[100];
char extract[50];
int i=0,j=0,k=0,endFlag=0;
printf("Input string: ");
fgets(input,sizeof(input),stdin);
input[strlen(input)-1] = '\0';
for(i=0;i<strlen(input);i++){
if(input[i] == '"'){
if(endFlag==0){
j =i+1;
while(input[j]!='"'){
extract[k] = input[j];
k++;
j++;
}
endFlag = 1;
}else{
endFlag =0;
}
//break;
}
}
extract[k] = '\0';
printf("Extract = %s\n",extract);
return 0;
}
Output:
$ ./test
Input string: extract "multiple" words "from" this "string"
Extract = multiplefromstring
Have you tried looking at the strchr function? You should be able to call that function twice to get pointers to the first and second instances of the " character and use a combination of memcpy and pointer arithmetic to get what you want.

Tokenizing user input in C (store in **arg)?

I'm attempting to write a simple shell like interface, that takes in a users input (by char) and stores it via a pointer to a pointer* (exactly how argv works). Here's my code:
char input[100];
char **argvInput;
char ch;
int charLoop = 0;
int wordCount = 0;
argvInput = malloc(25 * sizeof(char *));
while((ch = getc(stdin))) {
if ((ch == ' ' || ch == '\n') && charLoop != 0) {
input[charLoop] = '\0';
argvInput[wordCount] = malloc((charLoop + 1) * sizeof(char));
argvInput[wordCount] = input;
charLoop = 0;
wordCount++;
if (ch == '\n') {
break;
}
} else if (ch != ' ' && ch != '\n') {
input[charLoop] = ch;
charLoop++;
} else {
break;
}
}
If I loop through argvInput via:
int i = 0;
for (i = 0; i < wordCount; i++)
printf("Word %i: %s\n", i, argvInput[i]);
All of the values of argvInput[i] are whatever the last input assignment was. So if I type:
"happy days are coming soon", the output of the loop is:
Word 0: soon
Word 1: soon
Word 2: soon
Word 3: soon
Word 4: soon
I'm at a loss. Clearly each loop is overwriting the previous value, but I'm staring at the screen, unable to figure out why...
This line is your bane:
argvInput[wordCount] = input;
Doesn't matter that you allocate new space, if you're going to replace the pointer to it with another one (i.e. input).
Rather, use strncpy to extract parts of the input into argvInput[wordCount].
argvInput[wordCount] = input; is only making the pointer of argvInput[wordCount] point to the memory of input instead of copy the content of input into the new allocated memory. You should use memcpy or strcpy to correct your program.
After the pointer assignment the memory status looks like the image below. The memory allocated by malloc((charLoop + 1) * sizeof(char));, which are the grey ones in the graph, could not be accessed by your program anymore and this will lead to some memory leak issue. Please take care of that.
I suggest printing your argvInput pointers with %p, instead of %s, to identify this problem: printf("Word %i: %p\n", i, (void *) argvInput[i]);
What do you notice about the values it prints? How does this differ from the behaviour of argv? Try printing the pointers of argv: for (size_t x = 0; x < argc; x++) { printf("Word %zu: %p\n", x, (void *) argv[x]); }
Now that you've observed the problem, explaining it might become easier.
This code allocates memory, and stores a pointer to that memory in argvInput[wordCount]: argvInput[wordCount] = malloc((charLoop + 1) * sizeof(char)); (by the way, sizeof char is always 1 in C, so you're multiplying by 1 unnecessarily).
This code replaces that pointer to allocated memory with a pointer to input: argvInput[wordCount] = input; ... Hence, all of your items contain a pointer to the same array: input, and your allocated memory leaks because you lose reference to it. Clearly, this is the problematic line; It doesn't do what you initially thought it does.
It has been suggested that you replace your malloc call with a strdup call, and remove the problematic line. I don't like this suggestion, because strdup isn't in the C standard, and so it isn't required to exist.
strncpy will work, but it's unnecessarily complex. strcpy is guaranteed to work just as well because the destination array is allocated to be large enough to store the string. Hence, I recommend replacing the problematic line with strcpy(argvInput[wordCount], input);.
Another option that hasn't been explained in detail is strtok. It seems this is best left unexplored for now, because it would require too much modification to your code.
I have a bone to pick with this code: char ch; ch = getc(stdin); is wrong. getc returns an int for a reason: Any successful character read will be returned in the form of an unsigned char value, which can't possibly be negative. If getc encounters EOF or an error, it'll return a negative value. Once you assign the return value to ch, how do you differentiate between an error and a success?
Have you given any thought as to what happens if the first character is ' '? Currently, your code would break out of the loop. This seems like a bug, if your code is to mimic common argv parsing behaviours. Adapting this code to solve your problem might be a good idea:
for (int c = getc(stdin); c >= 0; c = getc(stdin)) {
if (c == '\n') {
/* Terminate your argv array and break out of the loop */
}
else if (c != ' ') {
/* Copy c into input */
}
else if (charLoop != 0) {
/* Allocate argvInput[wordCount] and copy input into it,
* reset charLoop and increment wordCount */
}
}

C: Reading in strings to a structure member using a do...while loop

I'm having a problem understanding how to read in a string to a structure member array. I have a structure called 'customer' and a member called 'char last_name[20]'. I prompt the user to enter in his last name and that last name is to be stored in the 'last_name[20]' variable. The condition is that I have to use a do...while loop.
Here's the code:
void get_customer_info(struct customer *p_customer_start, int customer_num)
{
struct customer *p_customer;
for (p_customer = p_customer_start; (p_customer - p_customer_start) <
customer_num; p_customer++)
{
printf("\nCustomer number %d: ", (p_customer - p_customer_start) + 1);
while (getchar() != NEW_LINE);
printf("\n Enter the customer's last name: ");
// *THIS PART IS THE PROBLEM*
do
{
p_customer->last_name = getchar();
p_customer->last_name++;
} while (*p_customer->last_name != NEW_LINE);
}
return;
}
Problem is, with that algorithm last_name[0] does not get checked, it moves to 'last_name[1]' before it gets checked for a new line. And yes, a do...while construct must be used (this is for a class).
I appreciate anyone's thoughts.
I think you may have much bigger problems there than you realise, with the attempted manipulation of an array address :-)
You can probably avoid all these problems with:
int i = 0;
do {
p_customer->last_name[i++] = getchar();
} while (p_customer->last_name[i-1] != NEW_LINE);
p_customer->last_name[i] = '\0';
Keep in mind that this is still open to buffer overflow problems (as was your original solution) since entering a name like "Pasquale Voldemort Fortescue del Mor" is going to blow out your 20-character array.
There are ways to fix that but it probably doesn't matter for classwork that much (it will in the real world but that comes with experience):
int i = 0;
do {
p_customer->last_name[i] = getchar();
if (i < sizeof (p_customer->last_name) - 1) // NEVER got to 20
i++;
} while (p_customer->last_name[i-1] != NEW_LINE);
p_customer->last_name[i] = '\0';
If you really want a pointer version of it, that's easy:
char *p = p_customer->last_name;
do {
*p = getchar();
if (p != &(p_customer->last_name[sizeof(p_customer->last_name) - 1])
p++;
} while (*(p-1) != NEW_LINE);
*p = '\0';
Ok, the solution with NO INDEXES would be;
char *pointer;
/* other code here */
pointer = p_customer->last_name
do {
*pointer = getchar();
pointer += sizeof( char );
} while ( *(pointer - sizeof( char ) )!= NEW_LINE );
if you want to be sure not to go out of array bound.......simply do not use do while =) (which I always reccomend, as you must read lots of line before understanding the loop condition (and in a multinested function this is't a real readibility problem
The code you posted won't compile. You mentioned that last_name is an array, but you can't assign to or increment arrays, so these two lines are invalid:
p_customer->last_name = getchar();
p_customer->last_name++;
Try doing something like this, which will get rid of this error as well as solve the problem of checking if the first character is a newline:
int i = 0;
char ch;
while ((ch = getchar()) != NEW_LINE)
p_customer->last_name[i++] = ch;
p_customer->last_name[i] = '\0'; // Don't forget the null terminator

Resources