I have a char array buffer that I am using to store characters that the user will input one by one. My code below works but has a few glitches that I can't figure out:
when I execute a printf to see what's in Buffer, it does fill up but I get garbage characters at the end
it won't stop at 8 characters despite being declared as char Buffer[8];
Can somebody please explain to me what is going on and perhaps how I could fix this? Thanks.
char Buffer[8]; //holds the byte stream
int i=0;
if (/* user input event has occurred */)
{
Buffer[i] = charInput;
i++;
// Display a response to input
printf("Buffer is %s!\n", Buffer);
}
Output:
tagBuffer is 1┬┬w!
tagBuffer is 12┬w!
tagBuffer is 123w!
tagBuffer is 1234!
tagBuffer is 12345!
tagBuffer is 123456=!
tagBuffer is 1234567!
tagBuffer is 12345678!
tagBuffer is 123456789!
You have to end the string with a \0 character. That's why they are called zero terminated strings.
It is also wise to allocate 1 extra char to hold the \0.
The only thing you are passing to the printf() function is a pointer to the first character of your string. printf() has no way of knowing the size of your array. (It doesn't even know if it's an actual array, since a pointer is just a memory address.)
printf() and all the standard c string functions assume that there is a 0 at the end of your string. printf() for example will keep printing characters in memory, starting at the char that you pass to the function, until it hits a 0.
Therefore you should change your code to something like this:
char Buffer[9]; //holds the byte stream
int i=0;
if( //user input event has occured )
{
Buffer[i] = charInput;
i++;
Buffer[i] = 0; // You can also assign the char '\0' to it to get the same result.
// Display a response to input
printf("Buffer is %s!\n", Buffer);
}
In addition to the previous comments about zero termination, you also have to accept responsibility for not overflowing your own buffer. It doesn't stop at 8 characters because your code is not stopping! You need something like the following (piggy-backing onto Jeremy's suggestion):
#define DATA_LENGTH 8
#define BUFFER_LENGTH (DATA_LENGTH + 1)
char Buffer[BUFFER_LENGTH]; //holds the byte stream
int charPos=0; //index to next character position to fill
while (charPos <= DATA_LENGTH ) { //user input event has occured
Buffer[i] = charInput;
Buffer[i+1] = '\0';
// Display a response to input
printf("Buffer is %s!\n", Buffer);
i++;
}
In other words, make sure to stop accepting data when the maximum length has been reached, regardless of what the environment tries to push at you.
If you are programming in C or C++, you have to remember that:
1) the strings are finished with a \0 character.
2) C does not have boundary check at strings, they are just character arrays.
It's odd that no-one has mentioned this possibility:
char Buffer[8]; //holds the byte stream
int i = 0;
while (i < sizeof(Buffer) && (charInput = get_the_users_character()) != EOF)
{
Buffer[i] = charInput;
i++;
// Display a response to input
printf("Buffer is %.*s!\n", i, Buffer);
}
This notation in the printf() format string specifies the maximum length of the string to be displayed, and does not require null termination (though null termination is ultimately the best way to go -- at least once you leave this loop).
The while loop is more plausible than a simple if, and this version ensures that you do not overflow the end of the buffer (but does not ensure you leave enough space for a trailing NUL '\0'. If you want to handle that, use sizeof(Buffer) - 1 and then add the NUL after the loop.
Since Buffer is not initialized, it starts with all 9 garbage values.
From the observed output, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th and 2 immediate next memory location(outside the array) elements are clearly 'T', 'T', 'W', '\0', '\0', '=', '\0', '\0', '\0'.
Strings consume all the characters up until they see NULL character. That is why, in every iteration, as the array elements are assigned one by one, buffer is printed up to the part where a garbage NULL is present.
That is to say, string has an undefined behavior if the character array doesn't end with '\0'. You can avoid this by having an extra space for '\0' at the end of the buffer.
You might also want to look into using a stringstream.
Related
I have a char array buffer that I am using to store characters that the user will input one by one. My code below works but has a few glitches that I can't figure out:
when I execute a printf to see what's in Buffer, it does fill up but I get garbage characters at the end
it won't stop at 8 characters despite being declared as char Buffer[8];
Can somebody please explain to me what is going on and perhaps how I could fix this? Thanks.
char Buffer[8]; //holds the byte stream
int i=0;
if (/* user input event has occurred */)
{
Buffer[i] = charInput;
i++;
// Display a response to input
printf("Buffer is %s!\n", Buffer);
}
Output:
tagBuffer is 1┬┬w!
tagBuffer is 12┬w!
tagBuffer is 123w!
tagBuffer is 1234!
tagBuffer is 12345!
tagBuffer is 123456=!
tagBuffer is 1234567!
tagBuffer is 12345678!
tagBuffer is 123456789!
You have to end the string with a \0 character. That's why they are called zero terminated strings.
It is also wise to allocate 1 extra char to hold the \0.
The only thing you are passing to the printf() function is a pointer to the first character of your string. printf() has no way of knowing the size of your array. (It doesn't even know if it's an actual array, since a pointer is just a memory address.)
printf() and all the standard c string functions assume that there is a 0 at the end of your string. printf() for example will keep printing characters in memory, starting at the char that you pass to the function, until it hits a 0.
Therefore you should change your code to something like this:
char Buffer[9]; //holds the byte stream
int i=0;
if( //user input event has occured )
{
Buffer[i] = charInput;
i++;
Buffer[i] = 0; // You can also assign the char '\0' to it to get the same result.
// Display a response to input
printf("Buffer is %s!\n", Buffer);
}
In addition to the previous comments about zero termination, you also have to accept responsibility for not overflowing your own buffer. It doesn't stop at 8 characters because your code is not stopping! You need something like the following (piggy-backing onto Jeremy's suggestion):
#define DATA_LENGTH 8
#define BUFFER_LENGTH (DATA_LENGTH + 1)
char Buffer[BUFFER_LENGTH]; //holds the byte stream
int charPos=0; //index to next character position to fill
while (charPos <= DATA_LENGTH ) { //user input event has occured
Buffer[i] = charInput;
Buffer[i+1] = '\0';
// Display a response to input
printf("Buffer is %s!\n", Buffer);
i++;
}
In other words, make sure to stop accepting data when the maximum length has been reached, regardless of what the environment tries to push at you.
If you are programming in C or C++, you have to remember that:
1) the strings are finished with a \0 character.
2) C does not have boundary check at strings, they are just character arrays.
It's odd that no-one has mentioned this possibility:
char Buffer[8]; //holds the byte stream
int i = 0;
while (i < sizeof(Buffer) && (charInput = get_the_users_character()) != EOF)
{
Buffer[i] = charInput;
i++;
// Display a response to input
printf("Buffer is %.*s!\n", i, Buffer);
}
This notation in the printf() format string specifies the maximum length of the string to be displayed, and does not require null termination (though null termination is ultimately the best way to go -- at least once you leave this loop).
The while loop is more plausible than a simple if, and this version ensures that you do not overflow the end of the buffer (but does not ensure you leave enough space for a trailing NUL '\0'. If you want to handle that, use sizeof(Buffer) - 1 and then add the NUL after the loop.
Since Buffer is not initialized, it starts with all 9 garbage values.
From the observed output, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th and 2 immediate next memory location(outside the array) elements are clearly 'T', 'T', 'W', '\0', '\0', '=', '\0', '\0', '\0'.
Strings consume all the characters up until they see NULL character. That is why, in every iteration, as the array elements are assigned one by one, buffer is printed up to the part where a garbage NULL is present.
That is to say, string has an undefined behavior if the character array doesn't end with '\0'. You can avoid this by having an extra space for '\0' at the end of the buffer.
You might also want to look into using a stringstream.
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];
I have a char array buffer that I am using to store characters that the user will input one by one. My code below works but has a few glitches that I can't figure out:
when I execute a printf to see what's in Buffer, it does fill up but I get garbage characters at the end
it won't stop at 8 characters despite being declared as char Buffer[8];
Can somebody please explain to me what is going on and perhaps how I could fix this? Thanks.
char Buffer[8]; //holds the byte stream
int i=0;
if (/* user input event has occurred */)
{
Buffer[i] = charInput;
i++;
// Display a response to input
printf("Buffer is %s!\n", Buffer);
}
Output:
tagBuffer is 1┬┬w!
tagBuffer is 12┬w!
tagBuffer is 123w!
tagBuffer is 1234!
tagBuffer is 12345!
tagBuffer is 123456=!
tagBuffer is 1234567!
tagBuffer is 12345678!
tagBuffer is 123456789!
You have to end the string with a \0 character. That's why they are called zero terminated strings.
It is also wise to allocate 1 extra char to hold the \0.
The only thing you are passing to the printf() function is a pointer to the first character of your string. printf() has no way of knowing the size of your array. (It doesn't even know if it's an actual array, since a pointer is just a memory address.)
printf() and all the standard c string functions assume that there is a 0 at the end of your string. printf() for example will keep printing characters in memory, starting at the char that you pass to the function, until it hits a 0.
Therefore you should change your code to something like this:
char Buffer[9]; //holds the byte stream
int i=0;
if( //user input event has occured )
{
Buffer[i] = charInput;
i++;
Buffer[i] = 0; // You can also assign the char '\0' to it to get the same result.
// Display a response to input
printf("Buffer is %s!\n", Buffer);
}
In addition to the previous comments about zero termination, you also have to accept responsibility for not overflowing your own buffer. It doesn't stop at 8 characters because your code is not stopping! You need something like the following (piggy-backing onto Jeremy's suggestion):
#define DATA_LENGTH 8
#define BUFFER_LENGTH (DATA_LENGTH + 1)
char Buffer[BUFFER_LENGTH]; //holds the byte stream
int charPos=0; //index to next character position to fill
while (charPos <= DATA_LENGTH ) { //user input event has occured
Buffer[i] = charInput;
Buffer[i+1] = '\0';
// Display a response to input
printf("Buffer is %s!\n", Buffer);
i++;
}
In other words, make sure to stop accepting data when the maximum length has been reached, regardless of what the environment tries to push at you.
If you are programming in C or C++, you have to remember that:
1) the strings are finished with a \0 character.
2) C does not have boundary check at strings, they are just character arrays.
It's odd that no-one has mentioned this possibility:
char Buffer[8]; //holds the byte stream
int i = 0;
while (i < sizeof(Buffer) && (charInput = get_the_users_character()) != EOF)
{
Buffer[i] = charInput;
i++;
// Display a response to input
printf("Buffer is %.*s!\n", i, Buffer);
}
This notation in the printf() format string specifies the maximum length of the string to be displayed, and does not require null termination (though null termination is ultimately the best way to go -- at least once you leave this loop).
The while loop is more plausible than a simple if, and this version ensures that you do not overflow the end of the buffer (but does not ensure you leave enough space for a trailing NUL '\0'. If you want to handle that, use sizeof(Buffer) - 1 and then add the NUL after the loop.
Since Buffer is not initialized, it starts with all 9 garbage values.
From the observed output, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th and 2 immediate next memory location(outside the array) elements are clearly 'T', 'T', 'W', '\0', '\0', '=', '\0', '\0', '\0'.
Strings consume all the characters up until they see NULL character. That is why, in every iteration, as the array elements are assigned one by one, buffer is printed up to the part where a garbage NULL is present.
That is to say, string has an undefined behavior if the character array doesn't end with '\0'. You can avoid this by having an extra space for '\0' at the end of the buffer.
You might also want to look into using a stringstream.
I have two char arrays (char string1[7] and char string2[256]) which I need to print in a specific format. Both strings have a random number of entries terminated with a '\0' null byte.
I need to print string1
followed by a space on 9th character
followed by string2 - which MUST begin printing from the 10th character onwards.
I have tried implementing this by copying the strings to a new array which I can print directly, however it is not working.
while(string2[i]!='\0')
{
if(i<9 && string1[i]!='\0')
{
Printline[i]=string1[i];
}
else if (i>9)
{
Printline[i]=string2[i];
}
i++;
}
printf("%s\n",Printline);
Any help is much appreciated :)
int main(void) {
char string1[7];
char string2[256];
strncpy(string1, "str1", 6);
strcpy(string2, "This is string 2.");
printf("%-8s %s", string1, string2);
return 0;
}
When compiled and run, the code above will print out:
str1 This is string 2.
The %-8s format specification says that, if the given string of characters is less than 8 characters long (not including '\0'), the string will be followed by whitespaces (blanks) to take up 8 rooms.
Furthermore, the 9th character is going to be a space and the rest will be filled up by string2.
Edit: strncpy function is used for string1 to ensure that no more than 6 characters will be copied from src to dest. Keep in mind that the 7th character will be a null-terminator ('\0').
I believe the following needs to be corrected/clarified and not going to post the code, so that you would have a chance to learn and try to fix it.
while(string2[i]!='\0') /* and further checks in the code, it appears that
the string2 has larger set of characters and
exceeds a count of 9 */
{
if (i<9 && string1[i]!='\0') /* What happens when (i < 9)
but string1[i] has already
reached the '\0'? */
{
Printline[i]=string1[i];
}
else if (i>9)
{
Printline[i]=string2[i];
}
/* What about (i == 9)? */
i++;
}
/* Not including '\0' from string2 before printing Printline
would eventually crash the program */
printf("%s\n",Printline);
I'm new to C programming. I am trying to make a program that takes some simple input. However I found that on comparison of my input string to what the user "meant" to input, there is an additional character at the end. I thought this might be a '\0' or a '\r' but that seems not to be the case. This is my snippet of code:
char* getUserInput(char* command, char $MYPATH[])
{
printf("myshell$ ");
fgets(command, 200, stdin);
printf("%u\n", (unsigned)strlen(command));
if ((command[(unsigned)strlen(command) - 1] == '\0') || (command[(unsigned)strlen(command) - 1] == '\r'))
{
printf("bye\n");
}
return command;
}
The code shows that when entering, say "exit" that 5 characters are entered. However I can't seem to figure out the identity of this last one. "Bye" never prints. Does anyone know what this mystery character could be?
The magical 5th element most probably is a newline character: \n
From man fgets() (emphasis by me):
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 '\0' is
stored after the last character in the buffer.
To prove this print out each character read by doing so:
char* getUserInput(char* command, char $MYPATH[])
{
printf("myshell$ ");
fgets(command, 200, stdin);
printf("%u\n", (unsigned)strlen(command));
{
size_t i = 0, len = strlen(command);
for (;i < len; ++i)
{
fprintf(stderr, "command[%zu]='%c' (%hhd or 0x%hhx)\n", i, command[i], command[i], command[i]);
}
}
...
assumptions
array indexes in c are started with 0
strlen returns length of string
so, if you have string "exit", this will be 5 symbols in array = e, x, i, t, \0, strlen return 4, but you're trying to decrement it by 1, so you're checking last symbol in string, instead on NULL terminator
to check NULL terminator use command[strlen(command)] - this will give you \0 always, so there is no sense in it
if you want to compare strings use strcmp function
UPDATE: issue with your program is because fgets appends \n symbol at then end of string:
A newline character makes fgets stop reading, but it is considered a
valid character by the function and included in the string copied to
str.
The reason you don't see the last char is because strlen() won't calculate '\0' into the string's length. So testing for '\0' wont succeed.
for instance, const char* a = "abc"; then strlen(a) will be 3. if you want to test it, you need to access it by command[strlen(command)]
The reason for getting strlen equals to 5 on "exit" is because fgets will append the '\n' character at the end of the input. You could test it by command[strlen(command) -1 ] == '\n'