Say I have:
....
char aLine;
char inputLine[1000];
scanf("%c", &aLine);
....
Now, I want to convert aLine into an array of char so that I can count how many characters in aLine. How can i do this?
Statement scanf("%c",... reads in a single character, so there is actually no need to count it. If you want to "convert" a single character into a string (for which you could then apply, for example, strlen()), write the character at a particular position. Don't forget to terminate the string with \0 (or 0x0) such that string functions like printf("%s"... or strlen() work correctly:
char aLine;
char inputLine[1000];
scanf("%c", &aLine);
inputLine[0] = aLine;
inputLine[1] = '\0';
printf("inputLine: '%s' has length %d", inputLine, strlen(inputLine));
or simply read in a complete line at once:
char inputLine[1000];
if (fgets(inputLine,1000,stdin)) {
printf("inputLine: '%s' has length %d", inputLine, strlen(inputLine));
}
Related
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 compiled this code using gcc (tdm-1) 5.1.0 and please tell me why the output doesn't contain "hello"
#include<stdio.h>
void main()
{
int i;
char st[20];
printf("Enter a string ");
scanf("%s",st);
for(i=0;i<20;i++)
{
printf("%c",st[i]);
}
}
Input:hello
Output: # #
You print all 20 elements of the array, but if the user entered a string smaller than that not all elements would be initialized. They would be indeterminate and seemingly random.
Remember that char strings in C are really called null-terminated byte strings. That null-terminated bit is important, and mean you can easily find the end of the string by checking the current character agains '\0' (which is the terminator character).
Or you could just use the strlen function to get the length of the string instead:
for(i=0;i<strlen(st);i++) { ... }
Or use the "%s" format to print the string:
printf("%s", st);
Also note that without any protection the scanf function will allow you give longer input than is space for in the array, so you need to protect agains that, for example by limiting the amount of characters scanf will read:
scanf("%19s",st); // Write at most 19 character (*plus* terminator) to the string
Now for why your input doesn't seem to be printed, it's because the indeterminate contents of the uninitialized elements. While you're not going out of bounds of your array, you still go out of bounds of the actual string. Going out of bounds leads to undefined behavior.
What's probably is happening is that some of the "random" indeterminate contents happens to be a carriage return '\r', which moves the cursor to the start of the line and the output already written will be overwritten by the uninitialized elements in your array.
Here's a short example as Qubit already explained:
#include <stdio.h>
void main () {
char str1[20];
printf("Enter name: ");
scanf("%s", str1);
printf("Entered Name: %s", str1);
}
Here
char st[20];
st is a local variable & default array st contents are garbage not zero. So if you scan less than 20 characters into st, in that case remaining location of array st contains garbage, hence it's printing some junk data like # # in case of
char st[20];
printf("Enter a string ");
scanf("%s",st);
for(i=0;i<20;i++) {
printf("%c",st[i]);
}
& it's a bad practice as if user entered few char lets say 5 char, then your loop rotates 20 times, internally it will do more operations or consume more CPU cycle.
So if you want to print a char array char by char, then you should rotate a loop until \0 char encounters, for e.g
for(i=0;st[i];i++) { /* this fails when \0 encounters */
printf("%c",st[i]);
}
Or
as others suggested you can print char array st using single printf by using %s format specifier like
printf("%s\n",st); /*here printf starts printing from base address of st
and prints until \0 */
Also it's better to initialize char array st while declaring itself. for e.g
char st[20] ="";
When I construct a string like this:
char string[1] = {'a'};
printf("%s", string)
it returns a a4.
Why is there a four at the end? How can I get rid of it?
I choose this method because I need to make a string from character indexes, such as char array[4] = {string[i],string[j],string[k]};.
Your string should end with terminating char '\0'
You can do it by:
char string[2] = {'a','\0'};
Or:
char string[] = "a";
"strings" in C are essentially arrays of characters ending with the \0 character (null terminated).
So if you want an array of characters, what you did is fine, but it is not a "string". Dont try to print it as such.
If you would also like to print it or treat it as a "string", then increase it's length by 1, and add a '\0' char at the end.
The conversion specification %s is used to output strings that is a sequence of characters terminated by a zero character.
The array declared this way
char string[1] = {'a'};
does not contain a string.
So to output its elements you need to specify the exact number of characters you are going to output. For example
printf("%*.*s", 1, 1, string);
Otherwise reserve one more element in the array for the terminating zero and use the conversion specification %s. For example
char string[2] = {'a'};
printf( "%s", string );
In my program, I am making a char line[MAXLINE] and then using it in:
fgets(line, sizeof line, f);
I can then print this line with
printf("%s\n",line);
However, trying something like
printf("%s\n",line[10]);
warns me that line[10] is of type int, and something like
printf("%s\n",line + 10);
prints from character 10 onwards.
how can I just get the nth character of this string?
You can get the nth character like so:
char ch = line[10];
But you can't print it as a string, because it's not a string. Print it as a character:
printf("%c\n", line[10]);
What you are doing when you use %s in the format string in printf is printing the null-terminated string starting from the the provided pointer.
line+10 is the pointer to the 11th character in the string so it prints everything it finds in memory until it encounters /0 (null) character.
To print a single character you have to use %c in the format string.
printf("%c",line+10);
printf("%s\n",line + 10); // %s expects a char *
Instead print like this -
printf("%c\n",line + 10);
how can I just get the nth character of this string?
With strlen() function from <string.h> you can get length of string. Thus easily you can get the nth character. of the string.
The below will also work as a string in C is a char pointer to the first character. (Strings are terminated in memory with the character \0, that's how programs know where they end.)
line is a pointer to the first character and it can be advanced to the 10th character, as below (we have to advance it by 9, as no advance points to the first character).
* dereferences the pointer to get the actual value.
#include <stdio.h>
int main()
{
char line[] = "abcdefghijkl";
printf("%c\n", *(line+9));
return 0;
}
When I press a key(integer) on my keyboard. It does something like:
gchar *keypressed;
keypressed=gdk_keyval_name (event->keyval);
printf("The KeyEvent is: %s\n", keypressed); // Till here it is fine
I get segmentation fault when I do this:
char ch;
sprintf(ch, "%s\n", keypressed);
printf("The NewKeyEvent is: %s\n",ch);
I need to convert it as I am going to use the value in a switch case. Without converting it is not possible.
gchar is a typedef alias of char, so the problem is not with the type conversion. You need to allocate some space for the sprintf buffer.
Currently, you are passing a single uninitialized char to where a pointer should be. You should get a warning from the compiler, in addition to a segfault caused by undefined behavior.
To fix this, make an array of chars and pass it to sprintf instead:
char ch[10];
sprintf(ch, "%8s\n", keypressed);
printf("The NewKeyEvent is: %s\n", c);
Note the limit of 8 in the sprintf. This is because ch is of size 10, and we need two extra spots for '\n' and '\0'.
If you want only a single character from the keypressed string there are two ways:
Use array indexing, this way you can access any character in the string:
char ch = keypressed[x]; // Where `x` is the character number you want
Remember that array indexing starts from zero, so the first character in the string is number 0.
If you want the first character, you can also use the dereference operator
char ch = *keypressed;
This equivalent to
char ch = keypressed[0];