Shouldn't I get an error if my string goes over 9 characters long in this program?
// CString.c
// 2.22.11
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
{
char *aString = calloc(10, sizeof(char));
if (aString == NULL)
{
return 1;
}
printf("PLEASE ENTER A WORD: ");
scanf("%s", aString);
printf("YOU TYPED IN: %s\n", aString);
//printf("STRING LENGTH: %i\n", strlen(aString));
}
Thanks
blargman
You don't get a compiler error because the syntax is correct. What is incorrect is the logic and, what you get is undefined behavior because you are writing into memory past the end of the buffer.
Why is it undefined behavior? Well, you didn't allocate that memory which means it doesn't belong to you -- you are intruding into an area that is closed off with caution tape. Consider if your program is using the memory directly after the buffer. You have now overwritten that memory because you overran your buffer.
Consider using a size specifier like this:
scanf("%9s", aString);
so you dont overrun your buffer.
Yes, you got an error. And the most unfortunate part is that you don't know about it. You might know about it later on in the program when something mysteriously crashes (if you're lucky), or when your client's lawyers come to sue you (if you're not).
Related
int main(int argc, char* argv[]) {
char* string; //local variable for a character
string = (char*)malloc(sizeof(char));
char* yes = "yes";
printf("Do you want to play (y/n)?");
scanf_s("%s", string);
if (strcmp(yes, string) == 0) {
printf("Hello welcome...");
}
Above is my code. Essentially, I want to make a loop asking for the user to input yes, y to continue; n, no to discontinue. But I simplify it for the sake of simple codes. The program just output the question, I press enter yes and enter then it stops.
I cant figure out a way to do it using array syntax( char string[] way, although array and malloc are basically the same) so I use pointer and malloc instead.
I'm going mad because this is bugging me so much. The practice assignment only asks to input character 'y' 'n' using %c but i want to do it the %s.
Really appreciate any help, im really stuck now. Thank you so much
Your code has two significant problems. First, if you want to input a string of characters, your malloc call needs to allocate space for more than one character; you should allocate the maximum number of characters you think the user's input will contain plus one - strings in C have a zero (nul) character at the end, to mark the end of the string).
Second, when you use the scanf_s function to read in a string (using the %s format specifier, as you have done), then you need to add additional parameters (the size of the target string buffer) after each string argument.
Here's a modified version of your code with these (and a few other) corrections:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
char* string = malloc(5); //local variable for a character string (up to 5 chars)
char* yes = "yes";
printf("Do you want to play (y/n)?");
scanf_s("%s", string, 5);
if (strcmp(yes, string) == 0) {
printf("Hello welcome...");
}
free(string); // Don't forget to release the memory!
return 0; // Conventionally, return 0 for success or non-zero on error
}
Note 1: Each and every call to malloc (or calloc) should be paired with a call to free to release the allocated memory, or you will end up with memory leaks.
Note 2: Please read this post: Do I cast the result of malloc?
Note 3: Although most (all?) C compilers will not insist on it, it is good practice to explicitly add a return 0; (for success) statement at the end of the main function.
Please feel free to ask for any further clarification and/or explanation.
This question already has answers here:
Why does C's printf format string have both %c and %s?
(11 answers)
Closed 4 years ago.
In a nutshell, I have to be able to return the character in the middle of an input (char array) for part of our first C assignment. What I have so far, however, is code that returns "Segmentation fault (core dumped)". I read into this a little bit, and learned that essentially I may be trying to access/modify data that is "not available to me", so-to-speak. Here is my code:
#include <stdio.h>
#include <string.h>
char input[30];
int inputLen;
char midChar;
int main()
{
printf("Type in some text, and the press the Return/Enter key: ");
fgets(input,sizeof(input),stdin);
printf("\nYour input: %s",input);
inputLen = strlen(input)-1;
printf("Length of your input is %d characters.",inputLen);
if((inputLen % 2) == 0) {
midChar = input[(inputLen/2)+1]; // >>> PROBLEM HERE <<<
}
else {
midChar = input[((inputLen+1)/2)+1]; // >>> PROBLEM HERE <<<
}
printf("%s",midChar);
return 0;
}
The two lines with >>> PROBLEM HERE <<< are the lines which I believe I've narrowed down to be the source of the problem.
Please Note: I have taken an introductory class in Java, and last semester took a class half-devoted to MATLAB, so I do have a little bit of programming intuition -- However, I am a 100% beginner in C, so I would appreciate some clear elaboration behind any help you guys may offer. I am not familiar with most functions/syntax unique to C, so I'm sure there will be cringe-worthy lines of code above for those well-versed in this language. If this is the case, feel free to include any other tips in your answers. Thanks!
You're printing a char with %s, so the program is treating your input as a pointer (to a char array). It's not a valid such thing.
You meant %c for a single character.
Your compiler should tell you about this. Turn warnings on!
A late addition:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// This will be the default value if a string of length 0 is entered
char midChar = 0;
int inputLen;
int bufferLen = 31;
char* input = (char*)malloc(sizeof(char) * bufferLen);
printf("Type in some text, and the press the Return/Enter key: ");
fgets(input, bufferLen, stdin);
printf("\nYour input: %s", input);
inputLen = strlen(input);
if (input[inputLen - 1] == '\n') {
inputLen--; // ignore new line character
}
printf("Length of your input is %d characters.\n", inputLen);
if (inputLen > 0) {
midChar = input[inputLen / 2]; // take right of middle for even number
}
printf("%c\n", midChar);
return 0;
}
In your previous post you used sizeof(input) which is not recommended for reasons described in this post. It is better practice to hold the length of the array in a separate variable, here bufferLen.
Also the use of global variables here input inputLen midChar is generally discouraged as they lead to unexpected behaviour during linking and make program flow harder to understand.
I initialised the memory for the buffer dynamically so the bufferLen could be changed in the program.
When computing the length of the input one must consider the newline character \n which is retained if a small enough string is entered but not if the entered string exceeds the bufferLen.
For strings with even lengths I arbitrarily took the character to the right. The inputLen zero case is also handled.
This whole answer is only an addition to the first one which already found the bug correctly, because I was late to the party.
Other than print char problem, I think there is also a problem at where you indicated.
ex. if input string is abc, inputLen will be 3, midchar index should be at 1 since array index in C start from 0. However ((inputLen+1)/2)+1 gives 3. This probably won't directly cause the segfault but will give wrong answer.
You can replace
if((inputLen % 2) == 0) {
midChar = input[(inputLen/2)+1]; // >>> PROBLEM HERE <<<
}
else {
midChar = input[((inputLen+1)/2)+1]; // >>> PROBLEM HERE <<<
}
with
midChar = input[inputLen/2];
since C will truncate when doing integer division.
a b c -> 3/2 = 1
[0] [1] [2]
a b c d -> 4/2 = 2
[0] [1] [2] [3]
Other than that, you also need to make sure the inputLen is not 0
Although "pretty lady" (#LightnessRasesInOrbit) up here is correct, let me explain what is happening when you do this:
printf("%s\n", charVar);
or this:
printf("%s\n", intVar);
or this:
printf("%s\n", floatVar);
Or when you print things using pritnf() with %s. You have to understand how does printf ("%s", string) work!! So when printf gets %s it looks for C string or in other words, character array terminated with '\0'. If it does not '\0' it will segfault. In depth, printf() works like this:
char name[4];
printf("Hello ", name);
now printf does following:
gets the size of 1st variable ("Hello")
gets the size of 2nd variable (name) How? Simple by this loop:
int varSize;
for (varSize = 0; varSize != '\0'; ++varSize);
moves "Hello" into buffer
Determine the size of second parameter. How, by doing this:
does following
if ("%d")
// read intVar and attach it to the buffer
if ("%f")
// read floatVar and attach it to the buffer
if ("%s")
for (int i = 0; stringVar[i] != '\0'; ++i)
// push each char into the buffer
So I hope you see what is happening if one of for() loops does not find '\0' character. If you do good if you don't well it continues reading through until it segfaults.
NOTE:
This is oversimplified pseudo code on how printf() works and is not actual implementation, this is only for OP to understand what is going on.
What follows are abbreviated just to keep this question short (no check for null, etc.).
program1.c
main()
{
char *aString = calloc(10, sizeof(char));
printf("Enter string: ");
scanf("%s", aString);
printf("You typed in %s\n", aString);
}
program2.c
main()
{
char aString[10];
printf("Enter string: ");
scanf("%s", aString);
printf("You typed in %s\n", aString);
}
program1.c will let me enter characters seemingly forever. I've entered 2000+ characters and the program will execute without error, despite the fact that this is "undefined behavior".
program2.c will let me enter more than 10 characters, but if get close to like 30 or 40 characters, it will give me a segmentation fault.
Now my limited understanding from class and other tutorials tells me that both of these programs are doing the same thing under the hood --- setting aside a piece of memory intended to be an array of chars of length 10. But it seems that program2.c's implementation provides some degree of safety. Or is the segmentation fault error completely random when you exceed the granted memory space, and I just happen to be getting it with program2.c just because that's the mood my computer is in right now?
What is the difference between program1.c and program2.c, and which is the "safer" method of entering a string? I realize there are other methods which may be even better, but I'm curious about the comparison between just these two.
Although neither program is safe, the likely reason you are seeing the behavior is that program B allocates the array on the stack, and as soon as you get out of bounds you are overwriting other useful things like the stack frame of the scanf call.
Whereas program A allocates heap memory, and since you are not doing anything else in this toy program, the memory you are writing into is unused.
In any real program, both are equally unsafe.
Note: This out-of-bounds behavior is undefined by the C standard, and the compiler could theoretically be doing anything. But in most common real-world compilers, the above is most likely what actually happens.
The two are not the same under the hood.
program1 is calling calloc to allocate memory from the heap.
program2 has been compiled to reserve additional space on the stack when the function is called.
Both programs are exploitable because you are not checking any bounds when you call scanf(). He is free to write as many bytes as he wishes to either buffer. The solution here is scanf("%9s", aString), which tells scanf to only write up to 9+1 bytes.
What and where are the stack and heap?
Assuming a typical modern operating system, your program 1 does not crash because calloc had to request an entire page (4096 bytes of RAM, usually) from the OS to satisfy the request for 10 bytes. If you feed that program sufficiently many characters, it will crash. However, writing even one byte more than the overtly requested size (10 bytes) is forbidden, and has an excellent chance of corrupting the internal data structure used to keep track of "heap" allocations. It is probable that if you added another malloc or free call to this program, after the scanf, it would crash inside that malloc or free. By way of illustration, consider this program:
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *p = malloc(23);
memcpy(p, "abcdefghijklmnopqrstuvwx", 25);
char *q = malloc(1);
return 0;
}
➽
$ MALLOC_CHECK_=1 ./a.out
*** Error in `./a.out': malloc: top chunk is corrupt: 0x0000000001bc4020 ***
(On this system, copying only 24 bytes does not crash. Do not rely on this information.)
Program 2, meanwhile, is probably crashing not because the scanf call wrote all the way to unmapped memory (which, for similar reasons, would require far more bytes of input) but because data on the stack is very densely packed and it clobbered something critical, e.g. the address to which main should return.
In a program that does anything even a little more complicated than your examples, both "techniques" are equally dangerous -- both heap and stack overflows can and have lead to catastrophic security holes.
You explicitly asked for a comparison between your two unsafe techniques, but for the benefit of future readers I am going to describe two much better techniques for reading strings from standard input. If your C library includes it, the best option is getline, which (in a simple program like this) would be used like so:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *line = 0;
size_t n = 0;
ssize_t r;
fputs("Enter a string: ", stdout);
fflush(stdout);
r = getline(&line, &n, stdin);
if (r == -1) {
perror("getline");
return 1;
}
if (r > 0 && line[r-1] == '\n')
line[r-1] = '\0';
printf("You entered %s\n", line);
free(line);
return 0;
}
If you don't have getline, and you need to read an arbitrarily long string from the user, your best option is to implement getline yourself (gnulib has an implementation you can borrow, if your code can be released under the GPL). But an acceptable alternative in many cases is to place an upper limit on input length, at which point you can use fgets:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LEN 81
int main(void)
{
char *line = malloc(MAX_LINE_LEN);
size_t n;
fputs("Enter a string: ", stdout);
fflush(stdout);
if (!fgets(line, MAX_LINE_LEN, stdin)) {
perror("fgets");
return 1;
}
n = strlen(line);
if (line[n] != '\n') {
fprintf(stderr, "string too long - %u characters max\n", MAX_LINE_LEN);
return 1;
}
line[n] = '\0';
printf("You entered %s\n", line);
free(line);
return 0;
}
Notes:
sizeof(char) == 1 by definition; therefore, sizeof(char) should never appear in well-written code. If you want to use calloc to allocate a prezeroed array of characters, write calloc(1, nchars).
Never use scanf, fscanf, or sscanf.
Do not confuse fgets with gets. fgets is safe if used correctly; it is impossible to use gets safely.
Can anyone tell me why this code crashes? It's simple, if the length of the string is > than 16, ask again for a string. It works if I write control = 1 inside the if statement, but it should work the same without it, 'cause the value of control at that point is 1, am I right?
thans (I'm learning)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
int control = 1;
char word[16] ;
printf("Enter a word: ");
while(control == 1)
{
scanf("%s", word);
int len = strlen(word);
printf("Lenght is: %d\n", len);
if (len >= 16)
{
printf("Word lenght to long, enter a new one: ");
}
else
{
control = 0;
}
}
printf("This is the word: %s\n", word );
}
char word[16] allocates 16 bytes of store for a string.
scanf() then reads a string into that store.
If you read in more than the amount of allocated store, memory is corrupted after the end of the store.
That's why you crash.
The problem is that if the user types more than the 15 characters which you have allocated space for, then the computer will merrily write all of them in memory past the end of your array. This will result in "undefined behavior" including crashing your program.
As others have noted, your fundamental problem is that you're allocating 16 characters for the string, and scanf will happily allow you to write past those 16 characters into memory that doesn't belong to you.
Be aware that C will allow you to do this with arrays generally, and understand how standard C strings work: you need to null-terminate them, meaning that you'll always need an extra space in the array for a null-terminating character \0.
There is a way to limit scanf with respect to C strings, using a field width specifier with %s, like so:
char input[17]; // room for 16 characters plus null-terminator
// here scanf will stop after reading 16 characters:
scanf("%16s", input);
With this code, you can safely use scanf to fill your string with no more than 16 characters, and scanf will null-terminate the string for you.
But as others have also noted, scanf is pretty poor at handling user input. It's usually better to use fgets and manage the input string on your own, piece-by-piece.
This is my source code:
#include <stdio.h>
#include <string.h>
void main()
{
int broj_znakova,i=0;
char niz1[81],niz2[81];
printf("Enter something, for end Ctrl/c \n\n");
while(fgets(niz1,81,stdin)!=NULL)
{
continue;
}
printf("You just enter: %s \n",niz1);
printf("This string is long %d\n",(strlen(niz1)-1));
strcpy(niz1,niz2);
printf("niz2 is %s\n",niz2);
if(strcmp(niz1,niz2)==0)
{
printf("niz1 and niz2 is same\n");
}
else
{
printf("niz1 != niz2\n");
}
while(niz1[i]!='\n')
{
if(niz1[i]==' ')
{
broj_znakova ++;
i=i+1;
}
}
printf("Spaces in string = %d\n",broj_znakova);
}
When i press Ctrl/c i got a bunch of strange characters, can someone help???
I google something about flushing but i'm new :)
The contents of niz2 is not initialized. It will result in undefined behavior. Perhaps you meant to copy niz1 to niz2. If so, then you need to reverse the parameters in the strcpy call. With strcpy, the first parameter is the target.
Note too that the variable broj_znakova is never initialized.
C does not "zero out" information in memory (in general) so when it allocates variables, you get whatever is there in memory at the time (whether it is logically readable as words or not), if you are printing something without the system knowing this is a string then it will keep printing until it encounters a NULL terminating character, if there is none, it tries to print whatever is in memory and this produces the weird characters.
On this line
strcpy(niz1,niz2);
I believe your parameters are reverse, it should be strcpy(niz2, niz1); The strange characters you are seeing is because niz2[81] has memory allocated, but it's not "filled in". So you get whatever 'magical' data that allocation may contain. That is, until you put something in it, or do memset, etc.