String being cut short of two chars - c

I need to get a user-input string with a maximum length of 50 chars. Therefore I defined a MAX_STRING_LENGTH variable at 50 and the string is initalized with 51 characters. However, every time the input is greater than 48 characters, the string is cut from the last two characters. This is a school exercise and I can't use <string.h>.
#include <stdio.h>
#define MAX_STRING_LENGTH 50
int main(void)
{
int j=0;
char stringInput[MAX_STRING_LENGTH+1]; //string initialized.
printf("Please enter a valid string\n");
fgets(stringInput,MAX_STRING_LENGTH,stdin); //string input.
for(j=0;stringInput[j]!='\0';j++);
if(j<MAX_STRING_LENGTH+1)
{
j=j-1;
stringInput[j]='\0'; //remove newline if it exists
}
//...
return 0;
}
I don't understand why the string is losing 2 characters.
I am assuming that a newline(\n) is created always when using fgets (even if a full string of 50 characters is inputted), and I'm losing 1 character always(and therefore I have to increase the string size of the string). However I do not understand how the other character is lost.
I would appreciate your feedback. Thank you

In this call
fgets(stringInput,MAX_STRING_LENGTH,stdin);
you specified that at most MAX_STRING_LENGTH - 1 characters will be read in the array stringInput.
If you want that the array can contain a string with 50 characters (excluding the terminating zero) then you have to call fgets like
fgets(stringInput,MAX_STRING_LENGTH + 1,stdin);
But in this case the new line character that corresponds to the entered key Enter will still be in the input buffer if the user entered exactly 50 characters. To extract it you should declare the array at least like
char stringInput[MAX_STRING_LENGTH + 2];
and write the call like
fgets(stringInput,MAX_STRING_LENGTH + 2,stdin);
However it would be better initially to declare MAX_STRING_LENGTH equal to 52.

this little loop
for(j=0;stringInput[j]!='\0';j++);
if(j<MAX_STRING_LENGTH+1)
{
j=j-1;
stringInput[j]='\0'; //remove newline if it exists
}
removes the last character regardless of what it contains.

This is a [c] not a [c++] question.
Documentation for fgets

Related

Problem reading two strings with getchar() and then printing those strings in C

This is my code for two functions in C:
// Begin
void readTrain(Train_t *train){
printf("Name des Zugs:");
char name[STR];
getlinee(name, STR);
strcpy(train->name, name);
printf("Name des Drivers:");
char namedriver[STR];
getlinee(namedriver, STR);
strcpy(train->driver, namedriver);
}
void getlinee(char *str, long num){
char c;
int i = 0;
while(((c=getchar())!='\n') && (i<num)){
*str = c;
str++;
i++;
}
printf("i is %d\n", i);
*str = '\0';
fflush(stdin);
}
// End
So, with void getlinee(char *str, long num) function I want to get user input to first string char name[STR] and to second char namedriver[STR]. Maximal string size is STR (30 charachters) and if I have at the input more than 30 characters for first string ("Name des Zuges"), which will be stored in name[STR], after that I input second string, which will be stored in namedriver, and then printing FIRST string, I do not get the string from the user input (first 30 characters from input), but also the second string "attached" to this, I simply do not know why...otherwise it works good, if the limit of 30 characters is respected for the first string.
Here my output, when the input is larger than 30 characters for first string, problem is in the row 5 "Zugname", why I also have second string when I m printing just first one...:
Name des Zugs:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
i is 30
Name des Drivers:xxxxxxxx
i is 8
Zugname: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaxxxxxxxx
Drivername: xxxxxxxx
I think your issue is that your train->name is not properly terminated with '\0', as a consequence when you call printf("%s", train->name) the function keeps reading memory until it finds '\0'. In your case I guess your structure looks like:
struct Train_t {
//...
char name[STR];
char driver[STR];
//...
};
In getlinee() function, you write '\0' after the last character. In particular, if the input is more than 30 characters long, you copy the first 30 characters, then add '\0' at the 31-th character (name[30]). This is a first buffer overflow.
So where is this '\0' actually written? well, at name[30], even though your not supposed to write there. Then, if you have the structure above when you do strcpy(train->name, name); you will actually copy a 31-bytes long string: 30 chars into train->name, and the '\0' will overflow into train->driver[0]. This is the second buffer overflow.
After this, you override the train->driver buffer so the '\0' disappears and your data in memory basically looks like:
train->name = "aaa...aaa" // no '\0' at the end so printf won't stop reading here
train->driver = "xxx\0" // but there
You have an off-by-one error on your array sizes -- you have arrays of STR chars, and you read up to STR characters into them, but then you store a NUL terminator, requiring (up to) STR + 1 bytes total. So whenever you have a max size input, you run off the end of your array(s) and get undefined behavior.
Pass STR - 1 as the second argument to getlinee for the easiest fix.
Key issues
Size test in wrong order and off-by-one. ((c=getchar())!='\n') && (i<num) --> (i+1<num) && ((c=getchar())!='\n'). Else no room for the null character. Bad form to consume an excess character here.
getlinee() should be declared before first use. Tip: Enable all compiler warnings to save time.
Other
Use int c; not char c; to well distinguish the typical 257 different possible results from getchar().
fflush(stdin); is undefined behavior. Better code would consume excess characters in a line with other code.
void getlinee(char *str, long num) better with size_t num. size_t is the right size type for array sizing and indexing.
int i should be the same type as num.
Better code would also test for EOF.
while((i<num) && ((c=getchar())!='\n') && (c != EOF)){
A better design would return something from getlinee() to indicate success and identify troubles like end-of-file with nothing read, input error, too long a line and parameter trouble like str == NULL, num <= 0.
I believe you have a struct similar to this:
typedef struct train_s
{
//...
char name[STR];
char driver[STR];
//...
} Train_t;
When you attempt to write a '\0' to a string that is longer than STR (30 in this case), you actually write a '\0' to name[STR], which you don't have, since the last element of name with length STR has an index of STR-1 (29 in this case), so you are trying to write a '\0' outside your array.
And, since two strings in this struct are stored one after another, you are writing a '\0' to driver[0], which you immediately overwrite, hence when printing out name, printf doesn't find a '\0' until it reaches the end of driver, so it prints both.
Fixing this should be easy.
Just change:
while(((c=getchar())!='\n') && (i<num))
to:
while(((c=getchar())!='\n') && (i<num - 1))
Or, as I would do it, add 1 to array size:
char name[STR + 1];
char driver[STR + 1];

Variable reset after scanf

I wrote the below function :
typedef enum {GREEN,BLACK, WHITE} color;
void StartGame(Piece board[8][8])
{
color currentPlayer=WHITE;
char location[2];
int gameover=1;
while(gameover)
{
printf("%d\n",currentPlayer);
if(currentPlayer==WHITE)
printf(BOLDWHITE"White: Please select a piece:\n");
else
printf(BOLDBLACK"Black: Please select a piece:\n");
printf("%d\n",currentPlayer);
scanf("%s",location);
printf("%d\n",currentPlayer);
if(currentPlayer==WHITE)
currentPlayer=BLACK;
else
currentPlayer=WHITE;
}
}
I print the currentPlayer on any level to see what's going on -> here what I get:
2
White: Please select a piece:
2
a1
0
2
White: Please select a piece:
2
Why the current player is 0 after scanf? I didn't touch it.
The buffer location has only room for 2 characters and scanf puts an extra NUL character at end. Therefore you have a stack corruption issue. Just give more room to location, for example:
char location[8];
EDIT
Since you just want to read a string, I recommend you using fgets, which allows you to limit the number of read characters from the input string. Thus, my code would look like this:
char location[8];
...
fgets(location, sizeof(location), stdin); //instead of scanf, fgets reads at most one less than buffer's size characters.
You only have to worry about the fact that fgets puts a final end line character (\n) at the end, but this should not be a deal if you just process the 2 first characters of the string.
It seems you overwrite the memory occupied by currentPlayer when you enter a string in character array location. As it seen from the console output you enetered string a1. That to store it in array location it shall be defined at leat as
char location[3];
because scanf appends entered strings with the terminating zero.
It would be better if you would use function fgets instead.
You should use something like this:
sprintf(format, "%%%dX", sizeof(buffer));
fscanf(file, format, &buffer);

c function, that "uppercasing" a string

This is my target:
input: string with mixed ASCII characters (uppercase, lowercase, numbers, spaces)
output: string with only uppercase characters
I have this:
#include <stdio.h>
void csere(char s[]){
int i;
for(i=0; s[i]!='\0'; i++){
if('a'<=s[i] && s[i]<='z'){
s[i]-=32;
}
printf("%c", s[i]);
}
}
void main(){
char s[1];
scanf("%s", &s);
csere(s);
}
My problem is:
The function stops at the first 'space' character in the string.
I tried to change the s[i] != '\0' in the 'for' part for i <
strlen(s) or just for s[i], but I still get the same result.
Example: qwerty --> QWERTY, but qwe rty --> QWE
(smaller problem: The program only accepts strings with length less than 12, if i change the 1 to 0 in main function.)
Thanks for help. Sorry for bad English.
scanf only scans non-whitespace characters with the %s modifier. If you want to read everything on a string you should use fgets with stdin as the third parameter:
fgets(s, sizeof s, stdin);
If you really need to use scanf for homework or something, you should use something like:
scanf("%128[^\n]", s);
Also, take note you are not allocating enough space for the string, the fact that it has not crashed is just pure coincidence... you should allocate the space on your array:
char s[128]; // change 128 for max string size
Actually, the fgets() usage I wrote earlier would only read 1 character (including the terminator string) since you only put 1 character on the array... change the array size and it should work.
You could also just use toupper() on ctype.h, but I guess this is some kind of homework or practice.
Furthermore, if you are allowed to use pointers, this would be a shorter (and probably more performant although that'd have to be tested... compilers are good these days :-) ) way to convert to uppercase (notice though it changes your original char array, and doesn't print it, although that'd be easy to modify/add, I'll leave it to you):
void strupper(char *sptr) {
while (*sptr) {
if ((*sptr >= 'a' ) && (*sptr <= 'z')) *sptr -= 32;
sptr++;
}
}
From scanf
s
Matches a sequence of bytes that are not white-space characters. The application shall ensure that the corresponding argument is a pointer to the initial byte of an array of char, signed char, or unsigned char large enough to accept the sequence and a terminating null character code, which shall be added automatically.
This means, with %s, scanf reads a string until it encounters the first white space character. Therefore, your function converts the given string only to the first space.
To the second (smaller) problem, the array s must be large enough for the entire string given. Otherwise, you overwrite the stack space and get undefined behaviour. If you expect larger strings, you must increase the size of s, e.g.
char s[100];

How to change characters within an array of strings?

I'm quite new to C and as part of my task, I must remove the the newline character that is added at the end of a string using fgets().
My lecturer advised this method:
char names[20];
fgets(names,20,fp);
names[strlen(names)-1]='\0';
I've omitted some of the code as I'm only demonstrating the method.
However, in our task, we have to deal with arrays of strings.
I've tried...
names[strlen(names[i])-1]='\0';
but seems to only find the length of the string, deduct 1 and then use that number in the index which then sets a string further down the array to \0
Is there a way to access the individual characters of the strings?
I know I can access the strings using
names[i] // where i is the numeric index
but I need to access the individual characters within that string.
This is my first time posting on StackOverflow so please inform me if I haven't included enough detail or have formatted my question poorly.
Thanks in advance.
As noted, in C a string is an array of characters. So, you can access the individual characters like you access any array. For your task what you need to do is
char names[100][20];
//Now this declares 100 strings of size 20 each.
//To access a single character in the position '4' from string 0 you can write
printf("%c",names[0][3]);
//To modify the string in position 'i' you will use
names[i][strlen(names[i])-1]='\0';
The last line is very similar to what you have written for a single string.
With the first index 'i' you access the string in that position. and with the second index you access a particular character of that string.
Try this:
#include <stdio.h>
#include <string.h>
int main(void)
{
char names[10][10];
char c = 'A';
for(int index = 0; i < strlen(names) - 1)
{
names[0][index] = c++;
}
names[i][strlen(names[i])-1]='\0';
printf("%s", namws[0]);
return 0;
}
In c, string is actually an array of char.
So,
char[] charArray = "string";
charArray[0] will give you 's'.

Input an arbitrary number of strings from the user [duplicate]

This question already has answers here:
How can I read an input string of unknown length?
(11 answers)
Closed 4 years ago.
I want to read in an arbitrary number of strings, one at a time, using <stdio.h> in C.
I know that you can do this with integers using:
while (scanf("%d ", &integer))
but I cannot do:
while (scanf("%s", string))
How can I implement the above?
The input is on separate lines.
You usually want to use fgets to read input as strings, especially when you want one line of input to end up as one string.
You can also use fscanf with a scanset conversion to read a line at a time, such as:
char line[100], newline;
fscanf("%99[^\n]%c", line, &newline);
Then you can check whether newline=='\n' to determine whether you've read the entire line successfully, or the line was larger than the buffer you provided.
When you're trying to read line-oriented input, you normally want to avoid "%s" (even with a specified length) though, as this reads white-space delimited tokens, not entire lines.
Use a char array:
char charArray[100];
while (scanf("%s", &charArray))
I guess your problem is to terminate the loop. scanf returns the number of successful scanned elements. In case of a string, also the empty string is successful scanned. Thus, you need another criterion, e.g.
while(scanf("%s",string) && (strlen(string)!=0))
I did not completely understand what you were trying to do from your original question. When you said you wanted to read in an arbitrary number of strings, I took that to mean, you wanted your program to be able to read 0 to n strings. Unfortunately in C, you will either have to cap off the maximum number of strings you would ever want to read in like
#define MAX_NUMBER_OF_STRINGS_TO_READ 25, or get into some sophisticated memory allocation scheme to read a string in and then add it to dynamic memory (returned from malloc).
I took the cap the maximum number of strings approach and wrote the following snippet:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char charArray[5][25] = {0};
int main(int argc, char *argv[])
{
int in_idx = 0;
int out_idx = 0;
printf("\n\n%s\n", "Enter no more than 5 strings, no more than 25 characters long.");
while(fgets (charArray[in_idx], 25, stdin))
{
if('\n' == charArray[in_idx][0])
{
printf("%s\n", "Entry terminated with newline.");
break;
}
in_idx++;
}
for(out_idx=0; out_idx < (in_idx + 1); out_idx++)
{
printf("%s", charArray[out_idx]);
}
printf("\n%s\n", "Program ended.");
return 0;
}
I made the termination character a newline. If I only want two strings, I press Enter when I've entered the second string. I terminated fgets by looking for a '\n' in the first position of the character array.

Resources