scanf() not working properly? - c

char *str;
printf("Enter string:\n");
scanf("%s",str);
OUTPUT:
runtime-check failure#3
str is being used without being initialized

Allocate an array and read into that:
char str[100];
if (scanf("%99s", str) != 1)
...error...
Or, if you need a pointer, then:
char data[100];
char *str = data;
if (scanf("%99s", str) != 1)
...error...
Note the use of a length to prevent buffer overflow. Note that the length specified to scanf() et al is one less than the total length (an oddity based on ancient precedent; most code includes the null byte in the specified length — see fgets(), for example).
Remember that %s will skip past leading white space and then stop on the first white space after some non-white space character. In particular, it will leave the newline in the input stream, ready for the next input operation to read. If you want the whole line of input, then you should probably use fgets() and sscanf() rather than raw scanf() — in fact, very often you should use fgets() and sscanf() rather than scanf() or fscanf(), if only because it make sensible error reporting a lot easier.

Its an undefined behavior if you dont initialize it.You have an uninitialized pointer which is reading data into memory location which may eventually cause trouble for you. You've declared str as a pointer, but you haven't given it a valid location to point to; it initially contains some random value that may or may not be a writable memory address.Try to allocate memory to the char *str;
char *str = malloc(sizeof(char)*100);

char *str declares str as a pointer to char type. scanf("%s",str) will read only E from the entered string.

You might NOT want to use exactly scanf("%s") (or get in the habit of using it) as it is vulnerable to buffer overflow (i.e. might accept more characters than your buffer can hold). For a discussion on this see Disadvantages of scanf

You have to allocate memory before assigning some value to a pointer. Always remember that pointer points to a memory location and you have to tell him what memory location you want to assign for him. So, for doing that you have to do :
str = (char*)malloc(sizeof(char));
This will assign you 1byte of memory block. So, you can assign only one character in this memory block. For a string you have to assign as many blocks depending on the number of characters in the string.Say, "Stack" requires 5 character and 1 extra block for '\0'. So, you have to assign at least 6 memory block to him.
str = (char*)malloc(6*sizeof(char));
I hope this will help you to grow more concepts in C.

Related

Defining strings using pointers Vs. char arrays in C

I am confused about how pointers to characters work. when I run the following code, what happens?
int main()
{
char* word;
scanf("%s",word);
printf("%s",word;
}
the first line in the main is defining a pointer to char without initialization. scanf should store the word somewhere and give the address to the pointer, right? what if I input a big string, would it overwrite something in the memory?
And what happens in the first line in the following code other than defining a pointer to char. Does the compiler set some limits? or I can't exceed the size specified, right? If done, I will have a run time error, right? what is the difference between the two cases?
int main()
{
char word[100];
scanf("%s",word);
printf("%s",word;
}
What about pointers to other types? Can I just keep writing to the following places using offsets?
scanf should store the word somewhere and give the address to the pointer, right?
No. It is the other way around. You define the address where scanf shall store the value. As you fail to initialize the pointer to some valid address, you cause undefined behaviour that might result in a crash in best case or seem to work in worst case.
And what happens in the first line in the following code other than defining a pointer to char.
There is no pointer involved at all. An array is not a pointer. An array provides all the memory it needs to store all its members. A pointer doesn't do this.
Does the compiler set some limits? or I can't exceed the size specified, right?
You can write wherever you want. No one will prevent you from doing this. At least no from trying. If you write to some location that does not belong to the memory you allocated, you again cause undefined behaviour.
The function scanf requires that you pass it the address of a sufficiently large memory buffer for storing the string. If you don't do this, then you will be invoking undefined behavior (i.e. your program may crash).
Simply passing a wild pointer (i.e. an arbitrary memory address) is not sufficient. Rather, you must reserve the memory that you intend to use, for example by declaring an array or by using the function malloc.
Using the %s scanf conversion format specifier by itself is not a good idea, because even if the allocated memory buffer has a size of 100 characters, if the user types more than 99 characters (100 including the terminating null character), then the function will write to the array out of bounds, causing undefined behavior. Therefore, you should always limit the number of characters that are written, in this case by writing %99s instead of simply %s.
Also, before using the result of scanf, you should always check the return value of the function, and only use the result if the function was successful.
int main()
{
char word[100];
if ( scanf( "%99s", word ) == 1 )
printf( "%s\n", word );
else
printf( "input error!\n" );
}
what if I input a big string, would it overwrite something in the memory?
It doesn't have to be a "big" string. Writing even a "small" string to a wild pointer will cause undefined behavior and something important may be overwritten, or your program may crash.
And what happens in the first line in the following code other than defining a pointer to char. Does the compiler set some limits?
The line
char word[100];
will allocate an array of 100 characters, i.e. it will give you a memory buffer that is sufficiently large to store 100 characters. This does not give you a pointer. However, when using the array word in the line
scanf("%s",word);
the array word will decay to a pointer to the first element.
Does the compiler set some limits? or I can't exceed the size specified, right?
The compiler won't prevent you from writing to the array out of bounds, but if you allow this to happen, then your program will have undefined behavior (i.e. your program may crash). Therefore, you probably don't want to allow that to happen.
If done, I will have a run time error, right?
If you are lucky, then yes, your program will crash immediately and you will easily be able to identify and fix the bug. If you are unlucky, then no, your program won't crash, but will work as intended, and you won't notice the bug for a very long time, until much later in development, when one day the bug starts overwriting something important in your program. In that case, the bug will probably be hard to diagnose.
This is because C is not a memory-safe language.
However, because these kinds of bugs are often hard to find, there are tools which can help detect these kinds of bugs, such as valgrind and AddressSanitizer.
According to the description of the conversion specifier %s in the C Standard
If no l length modifier is present, the corresponding argument shall
be a pointer to the initial element of a character array large enough
to accept the sequence and a terminating null character, which will be
added automatically.
That is when you pass a pointer as an argument of the function that corresponds to the format %s it shall point to the first element of a character array where the input string will be stored. The character array shall be large enough to accommodate the entered string (including the appended terminating zero character '\0')
In the first program
int main()
{
char* word;
scanf("%s",word);
printf("%s",word;
}
the pointer word is uninitialized and has an indeterminate value. So these two statements
scanf("%s",word);
printf("%s",word;
invoke undefined behavior.
You need to provide a valid value of the pointer that will point to a character array. For example
char s[100];
char *word = s;
Or you can allocate memory dynamically like
char *word = malloc( 100 * sizeof( char ) );
In the second program
int main()
{
char word[100];
scanf("%s",word);
printf("%s",word;
}
the array word used as an argument is implicitly converted to a pointer to its first element. If you will enter a string that fits in the array with 100 elements then the program will behave correctly.
However if you will enter 100 or more characters without embedded spaces then the program again will have undefined behavior.
To avoid such a situation you can specify the maximum length of the string that can be read in the array word by using the length modifier the following way
scanf("%99s",word);
If you want to input a string that may have embedded spaces you should use another conversion specifier. For example
scanf("%99[^\n]", word );
or
scanf(" %99[^\n]", word );
Here are two demonstration programs that show the difference between the two conversion specifiers used to enter a string.
#include <stdio.h>
int main(void)
{
char word[100];
scanf( "%99s", word );
puts( word );
return 0;
}
If to enter the string
Hello Mohammed Elbagoury
then the program output will be
Hello
And the second program
#include <stdio.h>
int main(void)
{
char word[100];
scanf( "%99[^\n]", word );
puts( word );
return 0;
}
Again if to enter
Hello Mohammed Elbagoury
then the program output will be
Hello Mohammed Elbagoury
If you will enter more than 99 characters then only the first 99 characters will be stored in the array appended with the terminating zero character '\0'.
As for your this question
Can I just keep writing to the following places using offsets?
then you can use the pointer arithmetic to store data in any position of an array. for example
int a[10];
scanf( "%d", a + 5 );
In this case a number will be written in the element of the array a[5].
The above statement is equivalent to
scanf( "%d", &a[5] );

memory allocation for char pointer

I am actually supposed to dynamically store a string. I have tried the below,
It is printing everything but it terminating as soon as a space is included in my input. can someone explain is why?
Also what is the right way to do it :
int i;
char *a;
a=(char *)malloc(sizeof(char));
scanf("%s",a);
for(i=0;*(arr+i)!='\0';i++)
printf("%c",*(arr+i));
It is printing everything but it terminating ...
Consider your memory allocation statements:
char *a;
a=(char *)malloc(sizeof(char));
By allocating only sizeof(char) bytes to the buffer a, then attempting to write anything more than the null terminator to it, you are invoking undefined behavior. (Note: sizeof(char) in C is by definition equal to 1, always)
C strings are defined as a null terminated character array. You have allocated only one byte. The only legal C string possible is one containing only the null termination byte. But your code attempts to write much more, and in so doing encroaches on memory locations not owned by your process. So in general, when creating strings, follow two simple rules:
Determine max length of string you need
allocate memory to max length + 1 bytes to accommodate termination byte.
Example if max string is x characters long, create the memory for x + 1 characters:
char inputStr[] = {"This string is x char long"};
char string = malloc(strlen(inputStr) +1); //+1 for null byte
strcpy(string, inputStr);
Note, in C it is not recommended to cast the return of malloc() and family.
You've two problems with your code. Firstly, you only allocate enough space for 1 character and since strings have to be NUL terminated, the longest string you could have is 0 characters long. Since you don't know how long the text you're going to read in, you could start with an arbitrary size (say 1024).
a=malloc(1024);
Secondly, scanf will only read up to the next space when you use "%s". It also isn't constrained by the available space in a. A better way to to read in an entire line of text, is to use fgets like this
fgets(a,1024,stdin);
This will read up to 1023 characters or up to and including the next newline character. It will NUL terminate the string for you as well.
You can then print it as a string.
printf("%s",a);
char *a;
/* Initial memory allocation */
a = (char *) malloc(1024); // your buffer size is 1024
// do something with a
free(a);
Copy bellow string in your variable then print the string with "%s" as string and theres no need use of "%c" :
strcpy(a, "this is a string");
printf("String = %s", a);
Dont forget using of free(), if you dont use of this then you will get memory leak problem.

is this code correct?If yes then malloc is already assigning the addresses to name[i] variable then why strcpy is used?

Following is the piece of code
char str[20];
char *name[5];
for(i=0;i<5;i++){
printf("Enter a string");
gets(str);
name[i]=(char *)malloc(strlen(str));
strcpy(name[i],str);
}
When in line 5 address of each string(denoted by str variable) is stored in name[i] array, then why this code is copying each address into name[i] using strcpy()?
is this code correct?
Sorry, No. Please follow the below mentioned points.
Point 1
Please do not cast the return value of malloc() and family in C.
Point 2
malloc() is to allocate memory to the pointer. strcpy() is to fill the allocated memory. If you compare the code,
name[i]=malloc(<size>));
allocates memory of size bytes to name[i] pointer. but, the contains of the memory location is uninitialized or garbage.
strcpy(name[i],str);
it copies the containts of str to name[i]. After this, name[i] contains the same string as str.
Note:
That said, to strcpy() a string str, you need to malloc() for strlen(str) + 1 bytes, to have space for terminating null. Otherwise, you'll end up overrunning the allocated memory area which in turn invokes undefined behaviour.
Also, you should (IMHO, MUST) consider using fgets() over gets().
The strcpy() call copies the characters, not the pointer.
Also, you are under-allocating since you fail to include space for the terminating '\0' character. Thus, your code has undefined behavior.
So no, it's not correct (but the problem is not that it uses strcpy(), that's fine).
And perhaps it's not surprising that I too think that you should not cast the return value of malloc() in C.
Finally, you should never use gets(), it's very dangerous. Use fgets() instead, with a proper buffer size argument of course.
When you use malloc, you create a space in memory that equals the size of the string, but is an empty space, you have only an address.
You have to copy the value on the string to the name[i] array.
An analogy is, you have a pot with water, you can create another pot, but you only will have water on it, if you transfer from one to another.
the creation of the pot is the malloc function and the transfer of the contents is the strcpy.
char str[6]; //create a empty space for 6 characters
char *name[1]; //create a pointer for a location where
//the array will be stored, does not
//allocate any space
str = "abcdef" //assign letters to character array
name[1]=(char *)malloc(strlen(str+1)); //name[1] = _ _ _ _ _ _ _
//allocate space char array with
//size equal to str array plus 1
strcpy(name[1],str); //name[1] = a b c d e f /0
//copy the letters from one char
//array to the other
character array has 6 characters plus a null character to indicate end of array
Line 5 merely allocates space. The memory allocated by malloc() has unspecified values.
TL;DR;
malloc assigns memory for the process to use.
strcpy copies the required content into the malloced address space.

C - copy buffer to string - is it even possible?

is it possible to copy buffer to a string? strncpy can copy string into an allocated string array, i'm wondering if this is possible to do the opposite
char *buffer[50];
fgets(buffer, 50, stdin);
//how can i assign string in buffer to a single string (char)?
First, a C string is not just a char, but an array of char with the last element (or at least the last one that's counted as part of the string) set to the null character (numerically 0, also '\0' as a character constant).
Next, in the code you posted you probably meant char buffer[50] rather than char *buffer[50]... the version you have is an array of 50 char *s, but you need an array of 50 chars. After that's corrected, then...
Since fgets() always fills in a null char at the end of the string it read, buffer would already be a valid C string after you call fgets(). If you'd like to copy it to another string so you can reuse the buffer to read more input, you can use the usual string handling functions from <string.h>, such as strcpy(). Just make sure the string you copy it into is large enough to hold all the used characters plus a terminating null character.
This code copies the string into a newly malloc()ed string (error checking omitted):
char buffer[50];
char *str;
fgets(buffer,50,stdin);
str = malloc(strlen(buffer) + 1);
strcpy(str,buffer);
This code does the same, but copies to a char array on the stack (not malloc()ed):
char buffer[50];
char str[50];
fgets(buffer,50,stdin);
strcpy(str,buffer);
strlen() will tell you how many characters are used in the string, but doesn't count the terminating null (so you need to have one more character allocated than what strlen() returns). strcpy() will copy the characters and the null at the end from one string/buffer to another. It stops after the null, and doesn't know how much space you've allocated -- so you need to make sure it will find a null character before running out of space in the destination, or reaching the end of the source buffer. If in doubt, place a null at the end of the buffer yourself to make sure.
It should be char buffer[50]; and yes, you can then use strncpy (which does not care if it got a static or a heap allocated zone).
But I would recommend using getline in your case.
First of all, you must have:
char buffer[50];
because otherwise you have an array of 50 char *s which is not what you want. That is, you read 50 chars from input and create addresses from them (which means "boom"!)
Second, yes, you can use strncpy to copy. Note that a string is basically an array of chars, terminated by '\0' (NUL). So in this case, buffer is indeed a string. You would want to copy the string only if you want to keep the original and modify the second (or keep a copy of original and then modify buffer). Otherwise, you can safely use the same buffer as the desired string.
Third, I don't know how exactly your input looks like, but what you want to do, you can most likely do it better with *scanf functions.

having memcpy problem

char *a=NULL;
char *s=NULL;
a=(char *)calloc(1,(sizeof(char)));
s=(char *)calloc(1,(sizeof(char)));
a="DATA";
memcpy(s,a,(strlen(a)));
printf("%s",s);
Can you plz tell me why its printing DATA½½½½½½½½■ε■????How to print only DATA?? Thanks
Strings in C are terminated by a zero character value (nul).
strlen returns the number of characters before the zero.
So you are not copying the zero.
printf keeps going, printing whatever is in the memory after s until it hits a zero.
You also are only creating a buffer of size 1, so you are writing data over whatever is after s, and you leak the memory calloc'd to a before you set a to be a literal.
Allocate the memory for s after finding the length of the string, allocating one more byte to include the nul terminator, then copy a into s. You don't need to allocate anything for a as the C runtime looks after storing the literal "DATA".
strlen does only count the chars without the terminator '\0'.
Without this terminator printf does not know the end od the string.
Solution:
memcpy(s,a,(strlen(a)+1));
You are first allocating memory, then throwing that memory away by re-assigning the pointer using a string literal. Your arguments to calloc() also look very wrong.
Also, memcpy() is not a string copying function, it doesn't include the terminator. You should use strcpy().
The best way to print only DATA would seem to be
puts("DATA");
You need to be more clear on what you want to do, to get help with the pointers/allocations/copying.
Your
a="DATA";
trashes the pointer to the allocated memory. It does not copy "DATA" into the memory. Which however would be not enough to store it, since
a=(char *)calloc(1,(sizeof(char)));
allocates a single char. While
memcpy(s,a,(strlen(a)));
copies what is pointed now by a (string literal "DATA") to the memory which is pointed by s. But again, s points to a single char allocated, and copying more than 1 char will overwrite something and results in a bug.
strlen(a) gives you 4 (the length of "DATA") and memcpy copies exactly 4 char. But to know where a string ends, C uses the convention to put a final "null" char ('\0') to its end. So indeed "DATA" is, in memory, 'D' 'A' 'T' 'A' '\0'.
All string related function expect the null byte, and they don't stop printing until they find it.
To copy strings, use instead strcpy (or strncpy), it copies the string with its final null byte too. (strcpy is less "secure" since you can overflow the destination buffer).
But the biggest problem I can see here is that you reserve a single char only for a (and you trash it then) and s, so DATA\0 won't fit anywhere.
You are reserving space for 1 character so you are actually using the memory of some other variable when you are writing "DATA" (which is 4 characters + the trailing \0 to mark the end of the string).
a=(char *)calloc(1,(sizeof(char)));
For this example you would need 5 characters or more:
a=(char *)calloc(5, (sizeof(char)));
You need to store a terminating \0 after that DATA string so printf() will know to stop printing.
You could replace memcpy with strcat:
strcat(s, a);
should do it.
Note, however, that there's a bug earlier on:
calloc(1,sizeof(char))
will only allocate a single byte! That's certainly not enough! Depending on the implementation, your program may or may not crash.

Resources