How to format a user entered line? - c

THIS IS A DIFFERENT QUESTION ENTIRELY. THE OTHER ONE IS URL SPECIFIC MINE IS NOT. THAT WAS JUST AN EXAMPLE.
So here's my code:
main()
{
char input[150]; //Create a variable of type char named input to store user input
printf(" Enter a standard line: "); //Ask the user for some standard input
if (fgets(input, 150, stdin) == NULL) //Initiate a series of checks to make sure there is valid input
{
puts(" End-of-File or Input Error Detected. "); //If the end of the file is reached or there is a problem with input output a message
}
else if (input[0] == '\n') //If the user neglected to enter anything output a message
{
puts(" Oops! Looks like you forgot to enter something! ");
}
else
{
printf(" Here's what you entered: %s ", input); //If there is valid user input echo it back to the user
int i = 0;
while ( input[i] != '\n' )
{
if (input[i] = '/')
putchar("%2F");
i++
}
}
}
I have to replace and adjust the input line accordingly by replacing certain characters with their ASCII code.
For example:
1. user inputs: google.COM/search?client
2. program changes and prints back to the user as: GOOGLE.com%2FSEARCH%3FCLIENT
But the system gives me this long error message when I try to compile my code.
/home/cs/carroll/cssc0154/One/p1.c: In function 'main':
/home/cs/carroll/cssc0154/One/p1.c:41:5: warning: passing argument 1 of 'putchar' makes integer from pointer without a cast [enabled by default]
putchar("%2F");
^
In file included from /home/cs/carroll/cssc0154/One/p1.c:15:0:
/usr/include/stdio.h:580:12: note: expected 'int' but argument is of type 'char *'
extern int putchar (int __c);
Where am I going wrong?

You're trying to pass 3 characters '%' '2' 'f' to a function putchar() that expects one character.
Consider using
printf("%%2f")
instead of
putchar("%2f"), you'll get the same output in stdout.
Note: you have to escape the percent character in printf with (%).

Since I don't have the points to comment on the above...
Background:
C doesn't really have 'strings' - it has pointers to characters which it handles very much like arrays.
standard library functions expect the last value in the array to be '\0', and they will keep processing characters until one of these 'null characters' is read.
This line:
putchar("%2F");
Passes a pointer (char *) to 'putchar()' instead of an integer.
The warning is simply pointing out the type mismatch, because it's unlikely you meant to do that. (it is correct, this is a serious mistake which can crash or cause vulnerabilities depending on the way the called function operates)
Most machines/compilers nowadays are LP64. That means 'putchar()' expects a 32bit integer, and you are providing a 64bit pointer.
The reason this code:
int i = 0;
while ( input[i] != '\n' )
{
if (input[i] == '/')
puts("%2F");
i++
}
prints out "%2F" (I assume given the input "google.COM/search?client") is because it finds '/' once, and prints the string you provided "%2F". No other character executes a print statement.
If you added:
int i = 0;
while ( input[i] != '\n' )
{
if (input[i] == '/')
puts("%2F");
else
putc(intput[i]);
i++
}
you would get
google.COM%2F
search?client
because puts() prints a newline ('\n') after printing its input.
To avoid that you'll need to choose a different output function, and while many options are available, printf() is likely the best and certainly the most recognizable.
printf() prints 'formatted' text which uses '%' to indicate formatting options, so printing a single '%' requires you to 'escape' it which looks like "%%"
Here is a working example of what you're trying to do.
I replaced, what must be a large block of
if (input[i] == 'CHAR') printf("%%XX");
else if (input[i] == ...
by putting all the special characters in a string.
I simply check whether that string contains each character I'm about to print.
If the character is found, I print a '%' followed by the character's hex value. The "%02X" tells printf() to write the hex value with at least 2 characters and to put 0 in front if it needs to pad the value. Basically it will never write '9' but instead write '09'.
You could also use the isalpha() ... isalphanum() ... ispunct() functions to identify which types of characters you should encode.
#include <stdio.h>
#include <string.h>
int main(int argc, char ** argv)
{
char *decodeStr = "/:\\+";
int decodeLen = strlen(decodeStr);
while(--argc >= 0 && ++argv && *argv){
char *str = *argv;
for(int i = 0; str[i] != '\0'; i++){
if (NULL != memchr(decodeStr, str[i], decodeLen))
printf("%%%02X", str[i]);
else
putchar(str[i]);
}
putchar('\n');
}
return 0;
}
example run:
./test http://google.com/atest+with+things
http%3A%2F%2Fgoogle.com%2Fatest%2Bwith%2Bthings

Related

Specific case of c scanf()

Input : [1,3,2,4]
I want to make arr[4] = {1, 3, 2, 4} from this input using scanf(). How can I do this in C language?
It is possible to parse input such as you describe with scanf, but each scanf call will parse up to a maximum number of fields determined by the given format. Thus, to parse an arbitrary number of fields requires an arbitrary number of scanf calls.
In comments, you wrote that
I want to find a method to ignore '[', ']', ',' and only accept integer units.
Taking that as the focus of the question, and therefore ignoring the issues of how you allocate space for the integers to be read when you do not know in advance how many there will be, and assuming that you may not use input functions other than scanf, it seems like you are looking for something along these lines:
int value;
char delim[2] = { 0 };
// Scan and confirm the opening '['
value = 0;
if (scanf("[%n", &value) == EOF) {
// handle end of file or I/O error ...
} else if (value == 0) {
// handle input not starting with a '[' ...
// Note: value == zero because we set it so, and the %n directive went unprocessed
} else {
// if value != 0 then it's because a '[' was scanned and the %n was processed
assert(value == 1);
}
// scan the list items
do {
// One integer plus trailing delimiter, either ',' or ']'
switch(scanf("%d%1[],]", &value, delim)) {
case EOF:
// handle end of file or I/O error (before an integer is read) ...
break;
case 0:
// handle input not starting with an integer ...
// The input may be malformed, but this point will also be reached for an empty list
break;
case 1:
// handle malformed input starting with an integer (which has been scanned) ...
break;
case 2:
// handle valid (to this point) input. The scanned value needs to be stored somewhere ...
break;
default:
// cannot happen
assert(0);
}
// *delim contains the trailing delimiter that was scanned
} while (*delim == ',');
// assuming normal termination of the loop:
assert(*delim == ']');
Points to note:
it is essential to pay attention to the return value of scanf. Failure to do so and to respond appropriately will cause all manner of problems when unexpected input is presented.
the above will accept slightly more general input than you describe, with whitespace (including line terminators) permitted before each integer.
The directive %1[],] attempts to scan a 1-character string whose element is either ] or ,. This is a bit arcane. Also, because the input is scanned as a string, you must be sure to provide space for a string terminator to be written, too.
it would be easier to write a character-by-character parser for your specific format that does not rely on scanf. You could also use scanf to read one character at a time to feed such a parser, but that seems to violate the spirit of the exercise.
While I think that John Bollinger answer is pretty good and complete (even without considering the wonderful %1[[,]), I would go for a more compact and tolerant version like this:
#include <stdio.h>
size_t arr_input(int *arr, size_t max_size)
{
size_t n;
for (n = 0; n < max_size; ++n) {
char c;
int res = scanf("%c%d", &c, arr + n);
if (res != 2
|| (n == 0 && c != '[')
|| (n > 0 && c != ',')
|| (n > 0 && c == ']')) {
break;
}
}
return n;
}
int main(void)
{
char *test_strings[] = { "[1,2,3,4]", "[42]", "[1,1,2,3,5,8]", "[]",
"[10,20,30,40,50,60,70,80,90,100]", "[1,2,3]4" };
size_t test_strings_n = sizeof test_strings / sizeof *test_strings;
char filename[L_tmpnam];
tmpnam(filename);
for (size_t i = 0; i < test_strings_n; ++i) {
freopen(filename, "w+", stdin);
fputs(test_strings[i], stdin);
rewind(stdin);
int arr[9];
size_t num_elem = arr_input(arr, 9);
printf("%zu: %s -> ", i, test_strings[i]);
for (size_t j = 0; j < num_elem; ++j) {
printf("%d ", arr[j]);
}
printf("\n");
fclose(stdin);
}
remove(filename);
return 0;
}
The idea is that you allocate space for the maximum number of integers you accept, then ask the arr_input() function to fill it up to max_size elements.
The check after scanf() tries to cope with incorrect input, but is not very complete. If you trust your input to be correct (don't) you can even make it shorter, by dropping the three || cases.
The most complex thing was to write the test driver with tmp files, strings, reopening and such. Here I'd have loved to have std::istream to just drop a std::stringstream. The fact that the FILE interface doesn't support strings really bugs me.
int arr[4];
for(int i=0;i<4;i++) scanf("%d",&arr[i]);
Are you asking for this? I was little bit confused with your question, if this doesn't solve your query, then don't hesitate to ask again...
use scanf to read a string input from user then parse that input into an integer array
To parse you can use string function "find" to locate the "," and "[]" and then use "atoi" to convert string into integer to fill the destination input array.
Edit: find is a C++ function.
the C function is strchr

How to check if an index contains a symbol?

I want to check to make sure that a given string contained in an array called secretWord has no symbols in it (e.g. $ % & #). If it does have a symbol in it, I make the user re-enter the string. It takes advantage of recursion to keep asking until they enter a string that does not contain a symbol.
The only symbol I do accept is the NULL symbol (the symbol represented by the ASCII value of zero). This is because I fill all the empty space in the array with NULL symbols.
My function is as follows:
void checkForSymbols(char *array, int arraysize){ //Checks for symbols in the array and if there are any it recursively calls this function until it gets input without them.
for (int i = 0; i < arraysize; i++){
if (!isdigit(array[i]) && !isalpha(array[i]) && array[i] != (char) 0){
flushArray(array, arraysize);
printf("No symbols are allowed in the word. Please try again: ");
fgets(secretWord, sizeof(secretWord) - 1, stdin);
checkForSymbols(secretWord, sizeof(secretWord));
}//end if (!isdigit(array[i]) && !isalpha(array[i]) && array[i] != 0)
else
continue;
}//end for(i = 0; i < sizeof(string[]); i++){
}//end checkForSymbols
The problem: When I enter any input (see example below), the if statement runs (it prints No symbols are allowed in the word. Please try again: and asks for new input).
I assume the problem obviously stems from the statement if (!isdigit(array[i]) && !isalpha(array[i]) && array[i] != (char) 0). But I have tried changing the (char) 0 part to '\0' and 0 as well and neither change had any effect.
How do I compare if what is in the index is a symbol, then? Why are strings without symbols setting this if statement off?
And if any of you are wondering what the "flushArray" method I used was, here it is:
void flushArray(char *array, int arraysize){ //Fills in the entire passed array with NULL characters
for (int i = 0; i < arraysize; i++){
array[i] = 0;
}
}//end flushArray
This function is called on the third line of my main() method, right after a print statement on the first line that asks users to input a word, and an fgets() statement on the second line that gets the input that this checkForSymbols function is used on.
As per request, an example would be if I input "Hello" as the secretWord string. The program then runs the function on it, and the if statement is for some reason triggered, causing it to
Replace all values stored in the secretWord array with the ASCII value of 0. (AKA NULL)
Prints No symbols are allowed in the word. Please try again: to the console.
Waits for new input that it will store in the secretWord array.
Calls the checkForSymbols() method on these new values stored in secretWord.
And no matter what you input as new secretWord, the checkForSymbols() method's if statement fires and it repeats steps 1 - 4 all over again.
Thank you for being patient and understanding with your help!
You can do something like this to find symbols in your code, put the code at proper location
#include <stdio.h>
#include <string.h>
int main () {
char invalids[] = "#.<#>";
char * temp;
temp=strchr(invalids,'s');//is s an invalid character?
if (temp!=NULL) {
printf ("Invalid character");
} else {
printf("Valid character");
}
return 0;
}
This will check if s is valid entry or not similarly for you can create an array and do something like this if array is not null terminated.
#include <string.h>
char false[] = { '#', '#', '&', '$', '<' }; // note last element isn't '\0'
if (memchr(false, 'a', sizeof(false)){
// do stuff
}
memchr is used if your array is not null terminated.
As suggested by #David C. Rankin you can also use strpbrk like
#include <stdio.h>
#include <string.h>
int main () {
const char str1[] = ",*##_$&+.!";
const char str2[] = "##"; //input string
char *ret;
ret = strpbrk(str1, str2);
if(ret) {
printf("First matching character: %c\n", *ret);
} else {
printf("Continue");
}
return(0);
}
The only symbol I do accept is the NULL symbol (the symbol represented by the ASCII value of zero). This is because I fill all the empty space in the array with NULL symbols.
NULL is a pointer; if you want a character value 0, you should use 0 or '\0'. I assume you're using memset or strncpy to ensure the trailing bytes are zero? Nope... What a shame, your MCVE could be so much shorter (and complete). :(
void checkForSymbols(char *array, int arraysize){
/* ... */
if (!isdigit(array[i]) && !isalpha(array[i]) /* ... */
As per section 7.4p1 of the C standard, ...
In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined.
Not all char values are representable as an unsigned char or equal to EOF, and so it's possible (and highly likely given the nature of this question) that the code above invokes undefined behaviour.
As you haven't completed your question (by providing an MCVE, and describing what errors are occuring) I'm assuming that the question you're trying to ask might be a duplicate of this question, this question, this question, this question and probably a whole lot of others... If so, did you try Googling the error message? That's probably the first thing you should've done. Should that fail in the future, ask a question about the error message!
As per request, an example would be if I input "Hello" as the secretWord string.
I assume secretWord is declared as char secretWord[] = "Hello"; in your example, and not char *secretWord = "Hello";. The two types are distinct, and your book should clarify that. If not, which book are you reading? I can probably recommend a better book, if you'd like.
Any attempt to modify a string literal (i.e. char *array = "Hello"; flushArray(array, ...)) is undefined behaviour, as explained by answers to this question (among many others, I'm sure).
It seems a solution to this problem might be available by using something like this...
In response to your comment, you are probably making it a bit tougher on yourself than it needs to be. You have two issues to deal with (one you are not seeing). The first being to check the input to validate only a-zA-Z0-9 are entered. (you know that). The second being you need to identify and remove the trailing '\n' read and included in your input by fgets. (that one may be tripping you up)
You don't show how the initial array is filled, but given your use of fgets on secretWord[1], I suspect you are also using fgets for array. Which is exactly what you should be using. However, you need to remove the '\n' included at the end of the buffer filled by fgets before you call checkforsymbols. Otherwise you have character 0xa (the '\n') at the end, which, of course, is not a-zA-Z0-9 and will cause your check to fail.
To remove the trailing '\n', all you need to do is check the last character in your buffer. If it is a '\n', then simply overwrite it with the nul-terminating character (either 0 or the equivalent character representation '\0' -- your choice). You simply need the length of the string (which you get with strlen from string.h) and then check if (string[len - 1] == '\n'). For example:
size_t len = strlen (str); /* get length of str */
if (str[len - 1] == '\n') /* check for trailing '\n' */
str[--len] = 0; /* overwrite with nul-byte */
A third issue, important, but not directly related to the comparison, is to always choose a type for your function that will return an indication of Success/Failure as needed. In your case the choice of void gives you nothing to check to determine whether there were any symbols found or not. You can choose any type you like int, char, char *, etc.. All will allow the return of a value to gauge success or failure. For testing strings, the normal choice is char *, returning a valid pointer on success or NULL on failure.
A fourth issue when taking input is you always need to handle the case where the user chooses to cancel input by generating a manual EOF with either ctrl+d on Linux or ctrl+z on windoze. The return of NULL by fgets gives you that ability. But with it (and every other input function), you have to check the return and make use of the return information in order to validate the user input. Simply check whether fgets returns NULL on your request for input, e.g.
if (!fgets (str, MAXS, stdin)) { /* read/validate input */
fprintf (stderr, "EOF received -> user canceled input.\n");
return 1; /* change as needed */
}
For your specific case where you only want a-zA-Z0-9, all you need to do is iterate down the string the user entered, checking each character to make sure it is a-zA-Z0-9 and return failure if anything else is encountered. This is made easy given that every string in C is nul-terminated. So you simply assign a pointer to the start of your string (e.g. char *p = str;) and then use either a for or while loop to check each character, e.g.
for (; *p != 0; p++) { do stuff }
that can be written in shorthand:
for (; *p; p++) { do stuff }
or use while:
while (*p) { do stuff; p++; }
Putting all of those pieces together, you could write your function to take a string as its only parameter and return NULL if a symbol is encountered, or return a pointer to your original string on success, e.g.
char *checkforsymbols (char *s)
{
if (!s || !*s) return NULL; /* validate string and not empty */
char *p = s; /* pointer to iterate over string */
for (; *p; p++) /* for each char in s */
if ((*p < 'a' || *p > 'z') && /* char is not a-z */
(*p < 'A' || *p > 'Z') && /* char is not A-Z */
(*p < '0' || *p > '9')) { /* char is not 0-9 */
fprintf (stderr, "error: '%c' not allowed in input.\n", *p);
return NULL; /* indicate failure */
}
return s; /* indicate success */
}
A short complete test routine could be:
#include <stdio.h>
#include <string.h>
#define MAXS 256
char *checkforsymbols (char *s);
int main (void) {
char str[MAXS] = "";
size_t len = 0;
for (;;) { /* loop until str w/o symbols */
printf (" enter string: "); /* prompt for user input */
if (!fgets (str, MAXS, stdin)) { /* read/validate input */
fprintf (stderr, "EOF received -> user canceled input.\n");
return 1;
}
len = strlen (str); /* get length of str */
if (str[len - 1] == '\n') /* check for trailing '\n' */
str[--len] = 0; /* overwrite with nul-byte */
if (checkforsymbols (str)) /* check for symbols */
break;
}
printf (" valid str: '%s'\n", str);
return 0;
}
char *checkforsymbols (char *s)
{
if (!s || !*s) return NULL; /* validate string and not empty */
char *p = s; /* pointer to iterate over string */
for (; *p; p++) /* for each char in s */
if ((*p < 'a' || *p > 'z') && /* char is not a-z */
(*p < 'A' || *p > 'Z') && /* char is not A-Z */
(*p < '0' || *p > '9')) { /* char is not 0-9 */
fprintf (stderr, "error: '%c' not allowed in input.\n", *p);
return NULL; /* indicate failure */
}
return s; /* indicate success */
}
Example Use/Output
$ ./bin/str_chksym
enter string: mydoghas$20worthoffleas
error: '$' not allowed in input.
enter string: Baddog!
error: '!' not allowed in input.
enter string: Okheisagood10yearolddog
valid str: 'Okheisagood10yearolddog'
or if the user cancels user input:
$ ./bin/str_chksym
enter string: EOF received -> user canceled input.
footnote 1.
C generally prefers the use of all lower-case variable names, while reserving all upper-case for macros and defines. Leave MixedCase or camelCase variable names for C++ and java. However, since this is a matter of style, this is completely up to you.

C duplicate character,character by character

I am trying to find if two characters following by one another are the same character. ie if i have this input "The oldd woman" I want to print next to second D "duplicate". Here is my code but I can't find out how can I do this coding. Here is my code:
void main()
{
char ch,ch2;
ch = getchar(); // getting the line of text
int i = 1;
ch2 = ch;
while (ch != '\n') // the loop will close if nothing entered
{
if (ch == ch2[&i]) {
printf("%c-duplicate", ch);
}
i++;
if (ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') { // checking for uppaercase vowel
printf("%c-upper case vowel", ch);
}
else if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') { // checking for lowecase vowel
printf("%c-lower case vowel", ch);
}
else if (ispunct(ch)) { // checking for punctuation
printf("%c-punctuation", ch);
}
else
putchar(ch);
printf("\n");
ch = getchar();
}
printf("\n");
}
}
I am setting the character to another variable and then checking them with the first if statement. The program should run character by character.
Below is an example that I believe is what you intended. c is the current character being read (note: it is type int) and c1 is the previous character read (initialized to -1 to insure it does not match the first test).
While you can compare A and E..., the string library provides strchr that easily allows testing if a single character is included within a larger string.
Rather than call printf for each duplicate or vowel, etc.., why not use sprintf to build a string containing all the criteria applicable to any one character. That way you only call printf once at the end of each iteration (depending on whether you are printing all or just those that match criteria). s is used as the buffer that holds the match information for each character, offset is simply the number of characters previously written to s. (you should check to insure you don't exceed the number of characters available in s (but that was unneeded here)
It is unclear whether you want to print each character in the input string, or just those you have matched so far. The code below with only output those characters that match one of the criteria (if no argument is given). If you would like to see all characters, then pass any value as the first argument to the program.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXL 32
int main (int argc, char **argv) {
char *uvowel = "AEIOU", *lvowel = "aeiou";
int c, c1 = -1;
while ((c = getchar()) != '\n' && c != EOF) {
char s[MAXL] = ""; /* description buffer */
int offset = 0; /* offset */
if (c == c1) /* new == old */
offset = sprintf (s, " duplicate");
if (strchr (uvowel, c)) /* upper-case? */
sprintf (s + offset, " upper-case vowel");
else if (strchr (lvowel, c)) /* lower-case? */
sprintf (s + offset, " lower-case vowel");
else if (ispunct (c)) /* punctuation? */
sprintf (s + offset, " punctuation");
else if (argc > 1) /* if printing all */
sprintf (s + offset, " other");
if (*s) /* print c and s */
printf (" %c - %s\n", c, s);
c1 = c; /* save last char read */
}
return 0;
}
Example Use/Output
$ echo "The oldd woman" | ./bin/classdup
e - lower-case vowel
o - lower-case vowel
d - duplicate
o - lower-case vowel
a - lower-case vowel
Pass any value as the first argument to print all characters:
$ echo "The oldd woman" | ./bin/classdup 1
T - other
h - other
e - lower-case vowel
- other
o - lower-case vowel
l - other
d - other
d - duplicate other
- other
w - other
o - lower-case vowel
m - other
a - lower-case vowel
n - other
Duplicate vowels
$ echo "womaan" | ./bin/classdup
o - lower-case vowel
a - lower-case vowel
a - duplicate lower-case vowel
Look things over and let me know if you have any questions. There are many ways to do this, this is just one that seemed close to your intent.
(note: you will want to pass the -Wno-unused-parameter compiler option to eliminate the warning about argv being unused, or just do a stub test somewhere in the code, e.g. if (argv[1]) {})
Worth answering to try and help understand variables and pointers I think.
To try and answer . . . as simply as possible . . . NOTE #1: the main problem/issue is that ch and ch2 are declared as single char variables. They can be 'a' or 'b' or '\n' or 0x20 or any other single char. They are NOT char arrays or pointers. You have a comment where you read one char 'ch = getchar() // getting the line of text', that comment is incorrect (although you do have good comments in showing what you are thinking in your example), anyway, this 'ch = getchar()' just gets a single char. Later you treat ch2 as an array.
char ch,ch2;
. . . then later:
if (ch == ch2[&i]) { // ouch, does that even compile? yes. oh dear. how do we explain this one?!
ouch! This is wrong because it treats ch2 as an array/pointer.
The way your loop is working now is ch2 is set once to the very first char read. And it never changes.
It may compile okay BUT does it give a warning? Actually, in fairness to you. I do not get a warning. gcc 4.8.2 is perfectly happy with ch2 being a char and doing (ch == ch2[&i]). Now, ch2[&i] may be syntactically valid code, it will compile ok. It will even run ok. BUT what does it mean? Is it semantically valid? Let's forget about this weird thing until later.
Note that you can have c compiling fine BUT it can be quite full of pointer errors and can crash/hang. So . . . be careful :-).
Try making a change like this:
ch = getchar(); // does not get the line of text, just gets one char
. . .
ch2 = 0; // for the first iteration of loop
if (ch == ch2) { // change from ch2[&i] - wow :-) very confused!
. . .
ch2 = ch; // set ch2 to the last char read before reading new
ch = getchar(); // read one new char
This makes the code work just using 2 chars. ch and ch2. You do not use i. You do not use an array or string or char pointer.
NOTE #1.1: ch2[&i] compiles and runs. BUT IT IS WRONG, OHHHH SOOOOOO WRONG. And weird. How does array access work in c? The syntax of c[&i] is "correct" (maybe depends on compiler). BUT please do not use this syntax! What does it mean? It is semantically dubious. Looks like perhaps intent was to use array of chars together with i. Quick example showing assigning and reading from array of chars correctly:
char s[100]; // string of 100 chars, accessing index below 0 and above 99 is bad
i=0;
s[i]='H'; // assign char 'H' to first letter of string (s[0])
i++; // increment i, i is now 2.
s[i]='i';
i++;
s[i]=0; // end string
printf("s[0]=%c s[1]=%c s[2]=%02x string:%s",s[0],s[1],s[2],s);
NOTE #1.2: ch2[&i] compiles and runs. How and why does it compile?
&i means the pointer to the variable i in memory
%p in printf will show pointer value
So try adding this to code sample:
printf("%p %p %p\n", &ch, &ch2, &i);
// ch2[i] will not compile for me, as ch2 is not an array. syntax error
// ch2[&i] DOES compile for me. But . . what is the value ?
// What does it mean. I do not know! Uncharted territory.
printf("ch2[&i]:%p:%02x\n",&i,ch2[&i]);
printf("ch2[&ch]:%p:%02x\n",&ch,ch2[&ch]);
printf("ch2[&ch2]:%p:%02x\n",&ch2,ch2[&ch2]);
I'm getting something like this each run the pointers change:
ch2[&i]:0xbfa0c54c:bfa0de71
ch2[&ch]:0xbfa0c54a:08
ch2[&ch2]:0xbfa0c54b:00
The discovered explaination:
Usually we declare an array e.g. 'int array[100];' where 100 is the size of array. array[0] is first element and array[99] is the last. We index the array using integer. Now, all arrays are pointers. SO *array is the same as array[0]. *(array+1) is the same as array[1].
So far so good.
Now *(1+array) is also the same as array[1].
We can say int i=7; And use array[i] or *(array+7) or *(7+array) OR i[array] to show the 7th element of the array. i[array] to any programmer should look very VERY WROOOONG (not syntactically wrong BUT philosophically/semantically/morally wrong!)
Okay. Fine. Calm down. Jeez. Now with 'char ch2;' ch2 is a single char. It is NOT an array. ch2[&i] works(works as in compiles and sometimes/mostly runs ok!!!) because the last(WROOOONG) i[array] notation is valid. Looking at TYPES is interesting:
i[array] === <type int>[<type int *>].
ch2[&i] === <type char>[<type int *>].
C happily and merrily casts char to int and int can be added to pointer or used as pointer. SO FINALLY IN CONCLUSION: the syntax ch2[&i] evaluates to an integer at offset of: &i(pointer to integer i) PLUS value of char ch2. There is no good reason to use this syntax! It's DANGEROUS. You end up accessing a memory location which may or may not be valid and as your pointer is pointer to single variable the location in not valid in reference to any other values.
See here: Why 'c[&i]' compiles while 'c[i]' doesn't?
NOTE #2: watch the bracketing {}. while and main closing } and indentation do not match in example. The program functions okay with this error. The putchar(ch) runs as part of the last else. The commands after that run at end of while loop.
NOTE #3 main should return int not void main optionally takes nothing '()' or '(int argc, char**argv)'.
Per other suggestions: Change ch == ch2[&i] This makes no sense here
Since you set ch = ch2 before the loop then the line
if(ch == ch2 )
(After you fix it) will always evaluate to true the first time around
Your else, is very confusing, if you have more than one line of code there you have to put in brackets
Keep in mind, when you enter your input you are actually submitting two characters eg ("e" AND "\n") because you press enter after you type the character and that counts
Try a little harder, meaning put an error message, put down the results of your attempts at a solution. It helps both us and you. It seems a little like you wrote this and just immediately want a fix. Programming gets harder, if you can't work through problems (with suggestions) then it's going to hurt a lot more, but it doesn't have to.
For a quick an dirty proof of concept, add another ch=getchar(); immediately after the one under your else. Note that the code below should run but doesn't do exactly what you want yet, you'll need to do some further debugging.
Edit 10/19/2016
Fixed the char2 issue you guys pointed out
Moved ch2 = ch to above the lines which get the new character
#include <stdio.h>
#include <ctype.h>
int main(){
char ch,ch2;
ch = getchar(); // getting the line of text
int i = 1;
ch2 = 0;
while (ch != '\n') // the loop will close if nothing entered
{
if (ch == ch2) {
printf("%c-duplicate", ch);
}
i++;
if (ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') { // checking for uppaercase vowel
printf("%c-upper case vowel", ch);
}
else if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') { // checking for lowecase vowel
printf("%c-lower case vowel", ch);
}
else if (ispunct(ch)) { // checking for punctuation
printf("%c-punctuation", ch);
}
printf("\n");
ch2 = ch;
ch = getchar();
ch = getchar();
}
printf("\n");
return 0;
}

Whitespace in C strings?

I have ran into a problem while learning to program in C. I am creating a program to translate a text into "rövarspråket" (you don't need to understand what it is to understand my problem). The program works great if I only insert one word, but when I add a space it just stop producing the output. Here'sn example:
If I insert "hello world", I want the output to be "hohelollolo wowororloldod", but instead it outputs "hohelollolo♀". Here's the code:
int main(){
char inputText[100], outputText[300];
int inputLength, ipTextNum, opTextNum;
scanf("%s", &inputText);
inputLength = strlen(inputText);
for(ipTextNum = 0; ipTextNum < inputLength; ipTextNum++){
if(inputText[ipTextNum] == 'a' || inputText[ipTextNum] == 'e' || inputText[ipTextNum] == 'i' || inputText[ipTextNum] == 'o' || inputText[ipTextNum] == 'u' || inputText[ipTextNum] == 'y' || inputText[ipTextNum] == 'å' || inputText[ipTextNum] == 'ä' || inputText[ipTextNum] == 'ö'){
outputText[opTextNum] = inputText[ipTextNum];
opTextNum++;
}
else {
outputText[opTextNum] = inputText[ipTextNum];
outputText[opTextNum+1] = 'o';
outputText[opTextNum+2] = inputText[ipTextNum];
opTextNum += 3;
}
}
printf("%s", outputText);
return 0;
}
If I also add inputText[ipTextNum] == ' ' to the if statement, it outputs the same thing as before, but without the ♀. Does anyone have a clue what the problem might be? I've tried to print the input, but it seems like all the text after the whitespace is terminated there too. Is whitespace even allowed in strings and if not, how do I work around this?
issue is here:
scanf("%s", &inputText);
there are actually two issues.. You want it to read an entire line I assume, so we don't use %s, we use "all characters except \n", then read the \n. The other issue is the &inputText.
scanf("%s", inputText);
is how it should be.. but this adds the entire line.
scanf("%[^\n]\n", inputText);
Go ahead and do your parsing on that, as long as you dont overflow!
scanf really shouldn't be used for strings with spaces because it does not accept them. You should really use fgets instead. See this answer for more information:
https://stackoverflow.com/a/1248017/2990189
Here is an example (from the above answer) to show how fgets works:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Maximum name size + 1. */
#define MAX_NAME_SZ 256
int main(int argC, char *argV[]) {
/* Allocate memory and check if okay. */
char *name = malloc (MAX_NAME_SZ);
if (name == NULL) {
printf ("No memory\n");
return 1;
}
/* Ask user for name. */
printf("What is your name? ");
/* Get the name, with size limit. */
fgets (name, MAX_NAME_SZ, stdin);
/* Remove trailing newline, if there. */
if ((strlen(name)>0) && (name[strlen (name) - 1] == '\n'))
name[strlen (name) - 1] = '\0';
/* Say hello. */
printf("Hello %s. Nice to meet you.\n", name);
/* Free memory and exit. */
free (name);
return 0;
}
As well as ensuring that the input does not overflow the buffer as other posters pointed out; another major issue is that you never null-terminate your output.
The printf("%s" knows when to stop outputting characters because it encounters a null byte. But you never wrote a null byte on the end of your output, which explains why there is a garbage character after it (and then you happened to have a null byte by chance in your buffer after the garbage).
After your loop, add in outputText[opTextNum] = 0; before the printf.
Of course, you also need to make sure your loop always stops with opTextNum < sizeof outputText being true. Since input has max string length 99 , then the max output that can be written is 3*99+1, so you're safe as things stand. If you decide to change your algorithm later you'll need to think about this again though.
Superficially, your problem is the use of scanf - it stops at the first space it encounters. Using fgets is usually the answer - and that might have been that. There was another problem in that you did not terminate your string (which led to the interesting last character - quite by chance, I must add), and you did not check for overflow in either the input or output buffers. Most of these points were made in other answers.
However - the problem is quite a bit more interesting, and harder, because you are using "non ascii" characters in your input. I am guessing your robbers have Scandinavian roots. This means that you not only need to worry about whitespace - you need to be using "wide characters".
I took the liberty of rewriting your example in "wide" form - meaning that it uses
fgetws - the wide equivalent of fgets
wprintf - the wide equivalent of printf
wcschr - the wide equivalent of strchr
As well as "wide" strings like L"wide string", "wide" characters like L'å', and "wide" format specifier %ls.
A stylistic problem with your code is that really long if statement that consisted of a long series of OR-ed comparisons with individual characters. You can do one of three things:
format more clearly with carriage returns and line continuations:
if( inputText[ipTextNum] == L'a' || \
inputText[ipTextNum] == L'e' || \
inputText[ipTextNum] == L'i' || \
inputText[ipTextNum] == L'o' || \
inputText[ipTextNum] == L'u' || \
inputText[ipTextNum] == L'y' || \
inputText[ipTextNum] == L'å' || \
inputText[ipTextNum] == L'ä' || \
inputText[ipTextNum] == L'ö')
Note: you did not test for space, so space is turned into o which is not what you want according to your description.
2. Replace the whole thing with wcschr which looks for a character in a string; by searching for the character in the string of vowels (this is what I did in the code below - including test for space); or
3. You could also create a function for yourself like
int isVowel(wchar_t c) {
return wcschr("aeiouyåäö ", c)!=0;
}
To make it even more compact/readable.
Anyway - here is the complete, annotated code:
#include <stdio.h> // <<<< dont forget your header files
#include <wchar.h> // <<<< to be able to use 'wide' characters: ö etc
// define the max size of input and output string:
#define IP_MAX 100
#define OP_MAX 300
int main(void) { // <<<<< use the correct function signature
wchar_t inputText[IP_MAX], outputText[OP_MAX];
int inputLength, ipTextNum, opTextNum=0; // <<< initialize opTextNum to zero!!
// scanf("%s", &inputText); // <<<< triple NO:
// 1) scanf stops at the first space
// 2) if the input is very long you overwrite your buffer
// 3) you are passing the POINTER to the pointer to char;
// you should use inputText not &inputText
fgetws(inputText, IP_MAX, stdin); // read at most IP_MAX characters into inputText including '\0'
inputLength = wcslen(inputText); // length of wide C string
inputText[--inputLength]='\0'; // strip carriage return
// printf("The length of the string entered is %d\n", inputLength);
wprintf(L"you entered \n'%ls'\n", inputText);
for(ipTextNum = 0; ipTextNum < inputLength && opTextNum < OP_MAX-3; ipTextNum++) {
if(wcschr(L"aeiouyåäö ", inputText[ipTextNum])) { // <<< include test for space too
outputText[opTextNum] = inputText[ipTextNum];
opTextNum++;
}
else {
outputText[opTextNum] = inputText[ipTextNum];
outputText[opTextNum+1] = 'o';
outputText[opTextNum+2] = inputText[ipTextNum];
opTextNum += 3;
}
}
outputText[opTextNum]=L'\0'; // nul terminate the string
wprintf(L"The robber said:\n'%ls'\n\n", outputText);
return 0;
}
Output:
hello world
you entered
'hello world'
The robber said:
'hohelollolo wowororloldod'

c detecting empty input for stdin

This seems like it should be a simple thing but after hours of searching I've found nothing...
I've got a function that reads an input string from stdin and sanitizes it. The problem is that when I hit enter without typing anything in, it apparently just reads in some junk from the input buffer.
In the following examples, the prompt is "input?" and everything that occurs after it on the same line is what I type. The line following the prompt echoes what the function has read.
First, here is what happens when I type something in both times. In this case, the function works exactly as intended.
input? abcd
abcd
input? efgh
efgh
Second, here is what happens when I type something in the first time, but just hit enter the second time:
input? abcd
abcd
input?
cd
And here is what happens when I just hit enter both times:
input?
y
input?
y
It happens to return either 'y' or '#' every time when I run it anew. 'y' is particularly dangerous for obvious reasons.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#define STRLEN 128
int main() {
char str[STRLEN];
promptString("input?", str);
printf("%s\n", str);
promptString("input?", str);
printf("%s\n", str);
return EXIT_SUCCESS;
}
void promptString(const char* _prompt, char* _writeTo) {
printf("%s ", _prompt);
fgets(_writeTo, STRLEN, stdin);
cleanString(_writeTo);
return;
}
void cleanString(char* _str) {
char temp[STRLEN];
int i = 0;
int j = 0;
while (_str[i] < 32 || _str[i] > 126)
i++;
while (_str[i] > 31 && _str[i] < 127) {
temp[j] = _str[i];
i++;
j++;
}
i = 0;
while (i < j) {
_str[i] = temp[i];
i++;
}
_str[i] = '\0';
return;
}
I've tried various methods (even the unsafe ones) of flushing the input buffer (fseek, rewind, fflush). None of it has fixed this.
How can I detect an empty input so that I can re-prompt, instead of this annoying and potentially dangerous behavior?
This part of cleanString
while (_str[i] < 32 || _str[i] > 126)
i++;
jumps over \0 when the string is empty.
You should add _str[i] != '\0' into the loop's condition.
To detect an empty string, simply check it's length just after the input:
do {
printf("%s ", _prompt);
fgets(_writeTo, STRLEN, stdin);
} while (strlen(_writeTo) < 2);
(comparing with two because of '\n' which fgets puts into the end of buffer)
Why do you have a bunch of variable names with leading underscores? That's nasty.
Anyway, the first thing you must do is check the return value of fgets. If it returns NULL, you didn't get any input. (You can then test feof or ferror to find out why you didn't get input.)
Moving on to cleanString, you have a while loop that consumes a sequence of non-printable characters (and you could use isprint for that instead of magic numbers), followed by a while loop that consumes a sequence of printable characters. If the input string doesn't consist of a sequence of non-printables followed by a sequence of printables, you will either consume too much or not enough. Why not use a single loop?
while(str[i]) {
if(isprint(str[i]))
temp[j++] = str[i];
++i;
}
This is guaranteed to consume the whole string until the \0 terminator, and it can't keep going past the terminator, and it copies the "good" characters to temp. I assume that's what you wanted.
You don't even really need to use a temp buffer, you could just copy from str[i] to str[j], since j can never get ahead of i you'll never be overwriting anything that you haven't already processed.

Resources