I created function that takes in a char pointer. I first get the string value from fgets, the input i'm entering is "rwx". When I enter that value, the strlen of it says it's length is 2 and when I look at the first index of the char array, it returns rw instead of r. May I ask where abouts am I going wrong for iterating through the string?
What I've tried:
int main()
{
char access[3];
while (ValidateAccess(access))
{
printf("Please enter your access\n");
fgets (access, 3, stdin);
}
return 0;
}
int ValidateAccess(char * access)
{
int length = strlen(access);
int r = 0,w = 0,x = 0,i;
printf("this is the length %d\n", length);
if (length == 0)
return 1;
for(i = 0; i < length; i++)
{
printf("this is the character: %s", &access[i]);
if (strcmp(&access[i], "r") == 0)
r++;
else if (strcmp(&access[i], "w") == 0)
w++;
else if (strcmp(&access[i], "x") == 0)
x++;
}
if (r <=1 && w <= 1 && x <= 1 )
return 0;
else
return 1;
}
when the program is ran this is the output
"this is the length 0"
Please enter your access
rwx
this is the length 2
this is the character: rw
man fgets is a very useful reading. Let me quote: "fgets() reads in at most one less than size characters from stream..."
The strings in C are expected to be terminated with \0 (zero byte). When you define access as an array of 3 elements, it has a room for a string of length 2 -- two characters plus terminating zero byte. When you call fgets saying that you have the space for 3 bytes, it reads two characters, puts them in the first two bytes, and puts terminating zero in the third byte.
Define access a having 4 bytes, and pass 4 to fgets.
Additionally, you are printing string not a char, so it prints everything to the terminating zero byte (that's where rw you see comes from). If you want to print a single character, use %c in format string, not %s (and you should pass a character, not a pointer then).
Try the following program and make sure you understand the output.
#include <stdio.h>
int main() {
char *foo = "barbaz";
printf("%c\n", foo[2]);
printf("%s\n", foo + 2);
}
Related
I am currently on a beginner course in C and was given an exercise requiring my program to check if the user input contains non-alphabets. I've figured to use the function isalpha() to check the user input and if it contains non-alphabets, the program should ask the user to enter another input.
Below is my current code:
#include <stdio.h>
#include <ctype.h>
#define MAX 13
int main() {
char player1[MAX];
int k = 0;
// Ask player 1 to type a word.
printf("Player 1, enter a word of no more than 12 letters: \n");
fgets(player1, MAX, stdin);
// // Loop over the word entered by player1
for (int i = 0; i < player1[i]; i++) {
// if any chars looped through is not an alphabet, print message.
if (isalpha((unsigned char)player1[i]) == 0) {
printf("Sorry, the word must contain only English letters.");
}
}
However, after testing it, I've derived a few cases from its results.
Case 1:
Entering without any input prints ("Sorry, the word must contain only English letters. ")
Case 2:
An input with 1 non-alphabetic character prints the 'sorry' message twice. Additionally, an input with 2 non-alphabetic characters print the 'sorry' message thrice. This implies that case 1 is true, since no input prints the message once, then adding a non-alphabetic prints the message twice.
Case 3:
An input of less than 10 characters(all alphabetic) prints out the sorry message also.
Case 4:
An input of more than 9 characters(all alphabetic) does not print out the sorry message, which satisfies my requirements.
Why are these the cases? I only require the message to print once if after looping through the user input, there's found to be a non-alphabetic character!
As #unwind has noted, the conditional of the OP for() loop is incorrect.
Good to trust to isalpha() but your code doesn't have to fondle each and every character. Another standard library function, strspn(), when supplied with your needs, can perform the looping work for you.
#include <stdio.h>
#include <string.h>
#define MAX 12
int main() {
char player1[ MAX + 1 + 1 ]; // buffer size for fgets() 12 + '\n' + '\0'
char *permissible =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Ask player 1 to type a word.
printf("Player 1, enter a word of no more than %d letters: \n", MAX);
fgets(player1, sizeof player1, stdin);
if( player1[ strspn( player1, permissible ) ] != '\n' )
printf("Sorry, the word must contain only English letters.");
return 0;
}
Strings in C are null-terminated, which means they contains an extra byte '\0' to mark the end of the string (character 0 in the ascii table), so you can only store 12 characters in a char array of size 13.
If you array contains a string smaller than 12 characters, since you loop over the whole array, you'll meet that null-terminating-byte, which fails isalpha(): it checks if character is in range ['A', 'Z'] or ['a', 'z']. Characters are just integers for your computers, so isalpha() checks if received value is is range [65, 90] or [97, 122], and 0 is not.
To be more precise, the notion of integer makes no sense for your computer, that's just how we interpret information, it's just a bunch of bits for your computer.
See ascii table: https://www.rapidtables.com/code/text/ascii-table.html
By having a fixed size buffer, you'll have garbage after the contained string if the string doesn't take all the space.
You have 2 conditions to stop iterating:
end of array, to prevent overflowing the array
end of string, to prevent mis-interpreting bytes in array which are further than string end
Error message might be printed several times, since you keep checking even after an error occured, you have to break the loop.
Below code doesn't meet mentioned problems
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define BUFFER_SIZE 13
#define MIN(a, b) (a < b ? a : b)
int main(void)
{
char player1[BUFFER_SIZE];
int maxIndex;
int i;
/* Ask player 1 to type a word */
printf("Player 1, enter a word of no more than 12 letters: \n");
fgets(player1, BUFFER_SIZE, stdin);
/*
* Max index for iteration, if string is lesser than 12 characters
* (excluding null-terminating byte '\0') stop on string end, otherwise
* loop over whole array
*/
maxIndex = MIN(strlen(player1) - 1, BUFFER_SIZE);
for (i = 0; i < maxIndex; i++) {
/* Print error if non-letters were entered */
if (isalpha(player1[i]) == 0) {
printf("Sorry, the word must contain only English letters.");
/* Error occured, no need to check further */
break;
}
}
/*
for (i = 0; i < maxIndex; i++)
printf("%d ", (int) player1[i]);
printf("\n%s\n", player1);*/
return 0;
}
The MIN() is a macro, a ternary expression which returns the smallest argument, nothing really complicated here.
But note that, when you enter the word, you press <Enter>, so your string contains a "go to next line" character (character '\n', n°10 in ascii table, as #Shawn mentioned in comments), so you have to stop before it: that's why I use strlen(player) - 1, string ends with "\n\0", and strlen() returns the number of bytes before '\0' (including '\n').
I've let a dump of the string at the end, you can modify the end-index there to see what's sent to isalpha(), replace maxIndex with BUFFER_SIZE.
This:
for (int i = 0; i < player1[i]; i++) {
loops from 0 up until (but not including) the code point value of the i:th character, updating i every time it loops. It will very likely access outside the array bounds, which is undefined behavior.
It should look for the terminator (or linefeed but let's keep it simple):
for (size_t i = 0; player1[i] != '\0'; ++i) {
to use the function isalpha() to check the user input and if it contains non-alphabets
Simply read one character at a time. No maximum needed.
#include <ctype.h>
#include <stdio.h>
int main(void) {
int ch;
int all_alpha = 1;
printf("Player 1, enter a line\n");
while ((ch = getchar()) != '\n' && ch != EOF) {
if (!isalpha(ch) {
all_alpha = 0;
}
}
if (!all_alpha) {
printf("Sorry, the line must contain only letters.");
}
}
int main()
{
int n = 100;
char a[n];
char b[ ]="house";
fgets(a,n-1,stdin); // type "house"
if (strcmp(a,b) == 0)
printf("The strings are equal.\n");
else
printf("The strings are not equal.\n");
return 0;
}
Reason why this
if (strcmp(a,b) == 0) { }
is not true because fgets() stores the \n at the end of buffer. So here array a looks like house and array b looks like house\n(If ENTER key was pressed after entering input char's) and strcmp(a,b) doesn't return 0.
From the manual page of fgets()
fgets() reads in at most one less than size characters from stream
and stores them into the buffer pointed to by s. Reading stops
after an EOF or a newline. If a newline is read, it is stored
into the buffer. A terminating null byte ('\0') is stored after
the last character in the buffer.
One way is to use strcspn() which removes the trailing \n. For e.g
fgets(a,n,stdin);
a[strcspn(a, "\n")] = 0;
Now compare the char array like
if (strcmp(a,b) == 0) {
printf("The strings are equal.\n");
}
else {
printf("The strings are not equal.\n");
}
In your example, this is what strcmp is comparing
strcmp("house\n", "house")
Which is false.
Here is a solution you could add to fix your code to the way (I assume) you expect it to work.
int main()
{
int n = 100;
char a[n];
char b[] = "house";
fgets(a, n-1, stdin);
a[strlen(a) - 1] ='\0'; //you may want to add length checking to prevent errors if user input is null
if (strcmp(a, b) == 0)
printf("The strings are eq\n");
else
printf("Not eq\n");
return 0;
}
I am a newbie to C and I was looking over some questions where I pondered upon a question where we need to scan in values using the users input. Example
1 2 3 45 6 7. So Automatically we scan these values into a 2D array.
One thing that troubles me is what If the user inputs
1 2 3 2 3 Josh, how can we ignore Josh and only scan in the values into the array.
I looked at using getchar and use a flag variable but I am unable to figure out the conundrum of differentiating between the integer and character.
/* This is something that I tried */
#include <stdio.h>
int main(int argc, char *argv[]) {
int a;
int b;
int A[10];
while (((a = getchar()) != '\n') && (b = 0)) {
if (!(a >= "A" && a <= "Z")) {
scanf("%d", A[b]);
}
b++;
}
}
}
I think one good method for achieving what you want is using scanf with the format "%s", which will read everything as a string, effectively splitting the input according to white spaces. From the manual:
s
Matches a sequence of non-white-space characters; the next
pointer must be a pointer to 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.
To convert the string to integer, you can use atoi. From the manual:
The atoi() function converts the initial portion of the string
pointed to by nptr to int.
So, if it converts the initial portion of the string into an integer, we can use that to identify what is a number and what's not.
You can build a simple "word detector" for atoi.
Using the function isalpha from ctype.h you can do:
int isword(char *buffer)
{
return isalpha(*buffer);
}
And rewriting your reading program you have:
#include <stdio.h>
#include <ctype.h>
int isword(char *buffer)
{
return isalpha(*buffer);
}
int main(void)
{
char input[200];
int num;
while (1) {
scanf("%s", input);
if (!strcmp(input, "exit")) break;
if (isword(input)) continue;
num = atoi(input);
printf("Got number: %d\n", num);
}
return 0;
}
You should keep in mind that the name isword is fallacious. This function will not detect if buffer is, in fact, a word. It only tests the first character and if that is a character it returns true. The reason for this is the way our base function itoa works. It will return zero if the first character of the buffer is not a number - and that's not what you want. So, if you have other needs, you can use this function as a base.
That's also the reason I wrote a separate function and not:
if (!isalpha(input[0]))
num = itoa(input);
else
continue;
The output (with your input):
$ ./draft
1 2 3 2 3 Josh
Got number: 1
Got number: 2
Got number: 3
Got number: 2
Got number: 3
exit
$
About assigments and &&
while (((a = getchar()) != '\n') && (b = 0))
As I said in a comment, this loop will never work because you're making a logical conjunction(AND) with an assignment that will always return zero. That means the loop condition will always evaluate to false.
In C, assignments return the value assigned. So, if you do
int a = (b = 10);
a will have now hold the value 10. In the same way, when you do
something && (b = 0)
You're effectively doing
something && 0
Which will always evaluate to false (if you remember the AND truth table):
p q p && q
---------------
0 0 0
0 1 0
1 0 0
1 1 1
Your code is completely wrong. I suggest to delete it.
You could use scanf with %d to read in numbers. If it returns 0, there is some invalid input. So, scan and discard a %s and repeat this process:
int num = -1;
while(num != 0)
{
printf("Enter a number, enter 0 to exit:");
if(scanf("%d", &num) == 0) /* If scanf failed */
{
printf("Invalid input found!");
scanf("%*s"); /* Get rid of the invalid input (a word) */
}
}
I want to write a program in C that fills an array p[MAX][N] of strings
I used this but i dont know which is the null string to enter when i give input.
#include <stdio.h>
#include <string.h>
#define R 3
#define C 8
int main()
{
int i;
char strings[R][C];
printf("***Table of Strings - Names***\n\n");
for(i=0;(i<R && gets(strings[i]));i++)
;
if(i==R)
printf("\n**Table Full - input terminated \n");
for(i=0;i<R;i++)
puts(strings[i]);
return 0;
}
First, never use gets(). It is inherently dangerous as it doesn't do any bounds checking on the memory you pass to it. Use fgets() instead:
for (i = 0; i < R && fgets(strings[i], C, stdin); ++i);
Note that fgets() will leave any new line ('\n') in the input at the end of the string, assuming that the whole line can fit in your buffer. If the whole line can't fit in your buffer, then it reads as much as can fit into your buffer (leaving room for and always appending a nul terminator), stops reading the input at that point and leaves the rest of the input on the stream. With C being so small in your program, such an occurrence is quite likely.
Alternatively, you could use getline() if it's available on your platform:
char *strings[R] = { 0 };
size_t cap;
for (i = 0; i < R && 0 <= getline(&strings[i], (cap = 0, &cap), stdin));
if (i == R)
printf("\n**Table Full - input terminated \n");
for (i = 0; i < R && strings[i]; ++i)
puts(strings[i]);
/* program done; clean up strings */
for (i = 0; i < R && strings[R]; ++i)
free(strings[R]);
getline() automatically dynamically (re)allocates the memory necessary to fit the next line from the input stream. It also leaves any new line ('\n') in the input at the end of the string.
Second, ctrl-D is typically used terminate the input to a program from a terminal.
It worked. I changed it to this
int main()
{
int i,j,max,thesi,sum=0,countCH=0,mikos=0;
char strings[R][C];
printf("***Table of Strings - Names***\n\n");
for(i=0;(i<R && fgets(strings[i],C,stdin ));i++)
;
if(i==R)
printf("\n**Table Full - input terminated \n");
for(i=0;i<R;i++)
fputs(strings[i],stdout);
//Euresh megistou string
max=0;
sum=0;
for(i=0;i<R;i++)
{
mikos=strlen(strings[i])-1;
sum+=mikos;
if(mikos>max)
{
max=mikos;
thesi=i;
}
}
printf("\nTo string me to megalitero mikos einai auto pou brisketai sthn %d seira \nkai einai to %s \nme mhkos %d",thesi+1,strings[thesi],max);
printf("\nO pinakas me ta strings periexei %d xaraktires\n",sum);
return 0;
}
It works just fine only that strlen counts all the chars of the string including null char why is that i dont get it?
I'm doing an exercise in K&R:
Write a program detab that replaces tabs in the input with the proper number of blanks to space to the next tab stop.
And this is what I have so far (w/o error checking on the file):
#include <stdio.h>
#define tab 2
#define MAX_LENGTH 1000
int main(int argc, char **argv)
{
FILE *fp = fopen(argv[1], "r+");
int c, n;
char buffer[MAX_LENGTH + 1];
for (n = 0; n < MAX_LENGTH && (c = fgetc(fp)) != EOF; ++n) {
if (c == '\t') {
for (int x = 0; x < tab; ++x)
buffer[n++] = ' ';
--n;
}
else
buffer[n] = c;
}
//buffer[n] = '\0';
//rewind(fp);
//fputs(buffer, fp);
printf("%s\n", buffer);
fclose(fp);
return 0;
}
It seems to work, but I'm wondering why \0 wasn't needed at the end. Was I just lucky?
Yes, you were lucky. To avoid this problem, you could have used fwrite, which doesn't require a null terminator (since you specify exactly how many bytes to write):
fwrite(buffer, 1, n, stdout);
You can tell printf(...) the (maximum) number of characters to print for a given string.
printf("%.*s\n", n, buffer);
See printf(3), section "The precision":
An optional precision, in the form of a period ('.') followed by an optional
decimal digit string. Instead of a decimal digit string one may write "*"
[...] to specify that the precision is given in
the next argument [...], which must be of type int. [...]
This gives [...] the maximum number of characters to be printed from a
string for s [...] conversions.
Live demo of printf ("%.*s\n", 5, "Hello, world!"): http://ideone.com/KHKLl.
You can initialize your buffer with:
memset(buffer, '\0', MAX_LENGTH + 1);
And you wont have to worry about the null termination.
As the other answers have pointed out, you were lucky that the array contained nulls at the right places.
You can initialise it when you create it using this shorthand:
char buffer[MAX_LENGTH + 1] = { 0 }; // all elements will be zero
Note that this is because the compiler will initialise unspecified entries with zeroes - so if you said
char buffer[MAX_LENGTH + 1] = { 'a' };
then the array would be {'a',0,0,0....}