String tokening in C - c

I have strings like "− · · · −" (Morse code) in an array, and want to tokenize each string to get each individual dot(.) and dash(−). A part of my code is given below:
char *code, *token;
char x;
char ch[4096];
code = &ch[0];
..
while((x = tolower(fgetc(fp))) != EOF){
printf("%c \n", x);
switch(x){
case 'a':
strcpy(code, "· −");
break;
case 'b':
strcpy(code, "− · · ·");
break;
case 'c':
strcpy(code, "− · − · ");
break;
case 'd':
strcpy(code, "− · ·");
break;
case 'e':
strcpy(code, "· ");
break;
case 'f':
strcpy(code, "· · − ·" );
break;
case 'g':
strcpy(code, "− − · ");
break;
case 'h':
}
if(x!= 10){
printf("Value read : %s \n", code);
token = strtok(code, " ");
while(token != NULL){
printf("CHARACTER: %s\n", token);
token = strtok(NULL, " ");
}
}
So, when the code array has "− − ·", I want the output to have:
CHARACTER: −
CHARACTER: −
CHARACTER: ·
However, the output is instead having CHARACTER: − − ·
I am new to string tokenizing, and might made a mistake somewhere there. Perhaps my delimiter is wrong, I am not sure. I hope I have provided enough information. Any help on this would be greatly appreciated.
Thanks in advance

The issue is that the (Unicode) whitespace character in the string literals (e.g. "· · − ·") is different to the whitespace character in the strtok() calls.
Run your source code through xxd and see for yourself.
As far as I can see, the spaces in the strcpy() calls are U+200A whereas the spaces in the strtok() calls are U+0020.

Strtok is not needed thing here (and you don't need those spaces either). If you want the individual characters from the string you could use a simple loop with a pointer over the original string:
char *current=&code;
Then make sure you loop until the end of string (null) character:
while (*current != 0x0) {
if(*current != ' ') {
printf("CHARACTER: %c \n", *current);
current ++;
}
}
What this does:
loops over the characters in code, using current as a pointer, and checking for the null terminator.
It then uses an if to check for a space, and if the character is not a space, format prints it - derefing the pointer to the char there.
Finally it increments the pointer.
Big warning: If you string is not zero terminated (a standard C string will be), this will start printing silly stuff.

Related

not taking input in c

char name[20];
printf("What is your name : ");
scanf("%s",name);
char user_grade;
printf("\nEnter your grade");
scanf("%c", user_grade);
switch(user_grade){
case 'A':
printf("%s you have passed the exams with great grade !",name);
break;
case 'B':
printf("%s you have passed the exams with good grades!",name);
break;
case 'C':
printf("%s you have passed the exams with nice grades!",name);
break;
case 'F':
printf("%s sorry you have failed the exam..");
break;
default:
printf("sorry your grade are invalid. retry again by typing valid grades");
break;
}
So the code has to ask the user their name and grade and check if they have passed the exams or not
but the code didn't take the grade input and outputs the result
Try scanf(" %c", &user_grade);
Two changes, put a space before %c so it will discard any leading whitespace, and pass the address of a variable with & so the function can change the variable.
scanf expects a pointer for an argument for each item of input. name is a pointer because you declared it as an array (although you're probably getting a compiler warning there).
Mainly the issue is that you passed user_grade in scanf("%c", user_grade); by value. You need to pass it by reference, using &: scanf("%c", &user_grade);
char name[20];, are you sure the name will be under 20 characters long? What if someone entered a name longer than 20 characters?:
scanf("%s",name); will just write it to the array irrespective of the size of the array, and your program will crash. So, use fgets(name, sizeof name, stdin);. But there is an issue here, fgets() also returns the newline character 0x0A/\n, so you need to remove it using name[strcspn(name, "\n")] = '\0';.
A fflush(stdin); after fgets() might be necessary in some situations here.
Next, you need to pass the variable user_grade by reference to scanf(), since it needs to memory address of user_grade to write to it. Use scanf(" %c", &user_grade);.
Here: CREDIT GOES TO #littleadv: to discard leading whitespace use: scanf(" %c", &user_grade);
For all of the printf() calls inside the switch, its best to add a \n to the end of each string to print on screen.
So, your final code would be:
char name[20] = {}; // initialize to be safe
printf("What is your name : ");
if (fgets(name, sizeof name, stdin) == NULL) {
// check for errors
puts("ERROR reading input!");
exit(1);
}
name[strcspn(name, "\n")] = '\0'; // needs <string.h>
char user_grade = '0'; // initialized to 0, maybe not needed; I would be on the safe side
printf("\nEnter your grade: ");
scanf(" %c", &user_grade); // pass by reference using `&`
switch (user_grade) {
case 'A':
printf("%s you have passed the exams with great grade !\n", name);
break;
case 'B':
printf("%s you have passed the exams with good grades!\n", name);
break;
case 'C':
printf("%s you have passed the exams with nice grades!\n", name);
break;
case 'F':
printf("%s sorry you have failed the exam..\n", name);
break;
default:
printf("sorry your grade are invalid. retry again by typing valid grades\n");
break;
}
Also, you could use switch (tolower(user_grade)) { (tolower() from <ctype.h>) to allow user to enter lowercase grades like a and still be accepted.
Edit:
#DavidC.Rankin suggested that I use fgets instead of scanf to avoid \n being left over and causing problems in loops, so here we can use this instead of scanf(" %c", &user_grade);:
char user_grade[1024] = {};
fgets(user_grade, 1024, stdin);
for (int i = 0; i < strlen(user_grade); i++) {
if (user_grade[i] != ' ' && user_grade[i] != '\t') {
// do the switch here
break;
}
}

I can't input a string in c

So I've tried so much but I can't input a string even using: fgets, gets, scanf, and scanf("%[^\n]%*c",pharse). I need a string with the spaces. It just jumps the code line of input I think.
Please answer with a explanation of why it doesn't work
https://repl.it/#YashKumar11/String#main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
const int DIMMAX=100;
char pharse[DIMMAX+1];
int stringLength;
int choice=0;
while(choice != '5'){
printf("1)Enter a new pharse.");
printf("\n2)");
printf("\n3)");
printf("\n4)");
printf("\n5)\n");
scanf("%d",&choice);
switch(choice){
case 1:
printf("\n=====================\n");
scanf ("%[^\n]%*c",pharse); //<-----------------------It jumps here
printf("\n=====================\n");
stringLength = strlen(pharse);
printf("%s",pharse);
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
default:
printf("\nNot a valid option.\n\n");
break;
}
}
return 0;
}
the statement to input the parase fails because the input for choice leaves a \n in the input stream.
When the second call to scanf() is made, it immediately returns (with a returned value of 0) because the first character input is \n.
suggest following each call to scanf() with:
int ch;
while( (ch = getchar()) != '\n' && ch != EOF );
that also implies that the format string of the second call to scanf() should have the %*c removed.
Your problem is not in the line that you try to read the string, but in the previous call to scanf()
scanf() was written to scanf formatted input. Keyboard input is not that. It can be everything except formatted. The user has over 100 keys to choose from
When the user types a '1' to input a phrase scanf() does not consume the newline. In fact the user can type 1 here we go to enter some text!
and then ENTER. And scanf() will be ok with just the '1'. The rest of the chars would be left there for the program to read. scanf() has no way to know what is left there.
Also scanf() return an int with the number of values read, and it can be zero if the user entered no digits. And you did not tested in your code.
Compare with your code a bit modified below
#define DIMMAX 100
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
char phrase[DIMMAX + 1];
int stringLength;
printf("1) Enter a new phrase");
printf("\n2)");
printf("\n3)");
printf("\n4)");
printf("\n5) Exit\n\nOption: ");
fgets(phrase, DIMMAX, stdin);
while (phrase[0] != '5')
{
switch (phrase[0]) {
case '1':
printf("\n=====================\n");
fgets(phrase, DIMMAX, stdin);
printf("\n=====================\n");
stringLength = strlen(phrase);
phrase[strlen(phrase) - 1] = 0; // deletes the '\n'
printf("Phrase: '%s', len = %zd\n\n", phrase, strlen(phrase));
break;
case '2':
break;
case '3':
break;
case '4':
break;
case '5':
break;
default:
printf("\n'%c' (dec %d) is not a valid option.\n\n",
phrase[0], phrase[0]);
break;
}
printf("1) Enter a new phrase");
printf("\n2)");
printf("\n3)");
printf("\n4)");
printf("\n5) Exit\n\nOption: ");
fgets(phrase, DIMMAX, stdin);
}; // while()
return 0;
}
Maybe it helps to understand.
Note that instead of stopping rigth at the digit, like scanf(), fgets() read up to and including the newline, so if you are using printf() and not puts() to output it, you must take the last byte off the string read

Replacing characters in a string using pointers

I'm supposed to make a program that replaces vowels in a string for numbers, without using and using pointers.
I used the commented printf in each switch statement to debug my program, and the output when the string is: aeiou, is:
4eiou
3iou
1ou
0u
2
and at the end when printing the string it just prints a blank line, when the output should be: 43102.
I'm doing something wrong that's replacing the complete string, but I can't figure it out. Can someone help me?
Thank you very much!
#include <stdio.h>
void changes(char* ptr) {
while (*ptr != '\0') {
switch(*ptr) {
case 'a':
*(ptr)='4';
//printf("%s\n", ptr);
break;
case 'e':
*(ptr)='3';
//printf("%s\n", ptr);
break;
case 'i':
*(ptr)='1';
//printf("%s\n", ptr);
break;
case 'o':
*(ptr)='0';
//printf("%s\n", ptr);
break;
case 'u':
*(ptr)='2';
//printf("%s\n", ptr);
break;
default:
break;
}
ptr++;
}
//Print the string
printf("%s\n", ptr);
}
int main() {
char sString[51];
char *charPtr = NULL;
charPtr = &sString[0];
printf("Introduce a string: ");
scanf("%[^\n]s", sString);
changes(charPtr);
}
You incrementing the pointer and printing what it points to using %s format specifier of printf. Keep a pointer to the beginning of the string and print it. You will see the desired behavior.
char *s = ptr;
while(*ptr != 0){
..
printf("%s",s);
}
This will print the whole string.(And you can notice the changes that you have made).

Is there something like a wildcard character for sscanf()

My string may or may not have some parameters, and so I want to insert that flexibility into my sscanf.
Eg My string can be "111|g|8|9|r|4|5" , Where the 3rd and 4th are optional paramaters, so we can have an input like this "111|g|||r|4|5"
Is there something like a wildcard character like * in regex which I can use ?
eg sscanf(mystr,"%d|%c|*|*|%c|%d|%d", &int1, &char1, &int2, &int3, &char2,&int4,&int5);
No you cannot.
scanf can only do simple conversions. If you need more complex matching, you must build a custom parser or use a richer library.
Here, the parsing can be done by hand:
store the current position in string
search the next '|' in the string with strchr => if not found, you have last token
store its position + 1 as a hold position
replace the '|' with a '\0'
the current token is the string starting at current position
set the current position to the hold position and iterate
I don't think you can be that selective with scanf so I suggest you use fgets and then sort the returned data.
No, not in the way you want to use it. However, there are alternatives.
As others have stated, you could use strsep() to separate the input.
The following code allows any of the fields to be empty, which in essence, is a more like a format code or wildcard (explained in regex as \d|*\|\w|*\|\d|*\|\d|*\|\w|*\|\d|*\|\d|*)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *my_string;
my_string = malloc(sizeof(char)*256);
char *my_string_split;
printf("Input: ");
fgets(my_string, 256, stdin);
char char1;
char char2;
int int1;
int int2;
int int3;
int int4;
int int5;
my_string_split = strsep(&my_string, "|");
for (int i = 0; my_string_split != NULL; i++) {
switch (i) {
case 0:
sscanf(my_string_split, "%d", &int1);
break;
case 1:
sscanf(my_string_split, "%c", &char1);
break;
case 2:
sscanf(my_string_split, "%d", &int2);
break;
case 3:
sscanf(my_string_split, "%d", &int3);
break;
case 4:
sscanf(my_string_split, "%c", &char2);
break;
case 5:
sscanf(my_string_split, "%d", &int4);
break;
case 6:
sscanf(my_string_split, "%d", &int5);
break;
}
my_string_split = strsep(&my_string, "|");
}
printf("%d|%c|%d|%d|%c|%d|%d", int1, char1, int2, int3, char2, int4, int5);
free(my_string);
return 0;
}
Normal input
Input: 111|g|8|9|r|4|5
111|g|8|9|r|4|5
Handles input with empty fields
Input: 111|g|||r|4|5
111|g|0|0|r|4|5
Also, if your system doesn't provide strsep() there's another stackoverflow question which has a solution to this: https://stackoverflow.com/a/8514474/6051408

Reading only one character (avoiding newline), then a string (for implementing simple CLI

I need to implement a simple CLI, which will initially read one character, and then will read the 2nd, or even 3rd part of the command specified by character.
For example, these would be the commands:
1. p all
2. r code
3. h
4. q
So as you can see there are commands that need only one character and others that need a character and a string.
What I've done so far is this:
//for the character
char init_command;
char command[30];
while(flag) {
read(STDIN_FILENO, &init_command, 1)
switch(init_command)
{
case ('p'):
if (fgets(command, sizeof(command), stdin) == NULL)
{
perror("fgets print");
exit(EXIT_FAILURE);
}
else
sscanf(command, "%s", command);
break;
case ('h'):
printfhelp();
break;
default:
printf("Undefined command\n");
break;
}
}
I've ommitted the part of r code and q commands as it is the same.
So, what happens here is that if I type this:
p all
Everything is ok.
But when I type this:
h
It prints the output of printhelp() and instantly prints the undefined command message.
Now, this has to be with the \n charatcter, but I am in difficulty of correcting it.
If the \n is seen as "valid input", just add it to the case structures as:
case '\n':
break;
This will allow other input to pass as error, but newlines ignored.
read(STDIN_FILENO, &init_command, 1);
fgets(command, sizeof(command), stdin);
switch(init_command)
{
case ('p'):
sscanf(command, "%s", command);
break;
case ('h'):
printfhelp();
break;
default:
printf("Undefined command\n");
break;
}

Resources