using scanf function with pointers to character - c

I have written the following piece of code:
int main() {
char arrays[12];
char *pointers;
scanf("%s", arrays);
scanf("%s", pointers);
printf("%s", arrays);
printf("%s", pointers);
return 0;
}
Why does it give an error when I write scanf("%s", pointers)?

char *pointers;
must be initialized. You can not scan string into pointers until you point it to some address. The computer needs to know where to store the value it reads from the keyboard.
int main() {
char arrays[12];
char *pointers = arrays;
scanf("%s", pointers);
printf("%s", pointers);
return 0;
}

Because you're writing to an address in memory that has not been initialized. Writing to memory pointer by an uninitialized pointer invokes undefined behaviour. Either allocate enough memory:
pointers = malloc(256);
if(!pointers)
perror("malloc");
else
scanf("%255s", pointers);
Or declare it as a static array:
char pointers[256];
You should also consider using fgets() instead of scanf().
You may want to read i you are interested in fgets():
Difference between scanf() and fgets()

char *pointers; creates a pointer variable.
pointers is the address pointed to by pointers, which is indeterminate by
default.
*pointers is the data in the address pointed to by pointers, which you cannot do until address is assigned.
Just do this.
char arrays[12];
char *pointers;
pointers = arrays;
scanf("%s",pointers);

pointers is being used without initialisation, like int x; printf("%d\n", x);. You need to make your pointer point to something before using it. Which book are you reading?

pointers is an unitialized pointer. You are not able to write into it. You shall allocate enough memory to store a string, as you did with arrays. With a pointer, it is possible to use dynamic allocation (cf. malloc).

Could you elaborate on the error, i'm not around a compiler right now.
But for scanf and printf to work you must have this at the top of your program:
#include <stdio.h>
#include <stdlib.h>
Both are standard libraries for C. IO contains scanf, I'm fairly sure printf is in the same. But until you know which libraries you need for which functions it doesn't hurt to include both standard libraries for every program. Try to use custom header files as well so you don't need mass #includes for every file.
Don't forget malloc statements for memory allocation.
But I'm unsure what you're attempting to do with your code, please elaborate?

Related

why couldn't use a pointer in gets in C? such as char *str replace char str[40] in gets(str)

#include <stdio.h>
int main ()
{
char str[40];
printf("Enter a string : \n");
gets(str);
printf("You entered: %s\n", str);
return 0;
};
in above code, if replace str to a pointer, char *str. Then NULL is out. Suppose gets defined by char *gets(char *str), it should use a pointer instead of array. All examples I saw are array not pointers. Thanks.
function gets() is depracted your libc/compiler might ignore it. try use fgets() instead.
#include <stdio.h>
int main ()
{
char str[40];
printf("Enter a string : \n");
if (fgets(str, sizeof(str), stdin) != NULL)
{
printf("You entered: %s\n", str);
}
return 0;
};
also if you want to don't use stack you need to give pointer that points allocated space. in code str also can be char *str = malloc(40); then change sizeof(str) to 40 since str is no longer stack.
Really interesting question, I have been asked this question a lot!
you should have a bit background of pointers and memory to understand what is happening.
first let's have a brief review about pointers and memory:
our computer have some memory and we can use it in programming, anything that we store (in runtime) for example an int, array of doubles, some complex struct and strings(that they are array of characters) should be somewhere in memory.
pointers contain address of somewhere in memory, some of them know about that memory (how to read/write value) some of them don't.
there is a special value for pointers (NULL) that means nowhere, if pointer is pointing to NULL, that pointer is pointing not nowhere (obviously nowhere is not a valid address in memory)
array is specific type of pointer, a const pointer that is pointing to already allocated memory in stack.
and about gets function: let's think we want to re-implement such function (namely my_gets) , how we suppose to do that? how to return a string (array of characters)?
these are options (as far as i know):
creating a local array in our function and fill it. then we should return it? no we cant! because that array is in stack of our function and after ending the function, our function data including this array will be popped automatically (handled by compiler).
although nobody forbid us from returning that array, but that would cause dangling pointer problem.
allocating some space rather than stack (heap) and fill that. this is perfectly fine and there is methods and do this! for example readline (not in ansi c, you can find it here) will do this. the drawback of this method is that you should take care of that memory and free it later, it also may be not to optimum way and you may should copy that string to your already allocated memory
the last way (and way that gets use) is getting a pointer that is already pointing to a valid memory and fill that memory. you already know that gets want a pointer as input, I add that, that pointer should point to a valid and accessible memory that gets can fill it. if pointer is pointing to NULL (or maybe uninitialized and pointing to some where random) gets will fail writing and cause undefined behavior (segmentation fault for example)
some final points:
array solution work because array name is pointer that pointing to valid memory (array in stack) so it's OK and easy to understand.
If we don't want to use array, we can point our pointer to a valid memory, we need to use malloc/calloc to allocate a block of memory. see this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size = 40 * sizeof(char);
char* p = malloc(size);
printf("Enter a string : \n");
if (fgets(p, size, stdin) != NULL) {
printf("You entered: %s\n", p);
}
free(p);
return 0;
}
gets is not secure because it doesn't care how much memory we have, it writes until and string ends and it may cause buffer overflow, better option (as people said) is fgets because it care memory size and will not exceed that. but my answer doesn't care it's fgets or gets.

C reading from a CSV file zeroes displayed after each record [duplicate]

I have written the following piece of code:
int main() {
char arrays[12];
char *pointers;
scanf("%s", arrays);
scanf("%s", pointers);
printf("%s", arrays);
printf("%s", pointers);
return 0;
}
Why does it give an error when I write scanf("%s", pointers)?
char *pointers;
must be initialized. You can not scan string into pointers until you point it to some address. The computer needs to know where to store the value it reads from the keyboard.
int main() {
char arrays[12];
char *pointers = arrays;
scanf("%s", pointers);
printf("%s", pointers);
return 0;
}
Because you're writing to an address in memory that has not been initialized. Writing to memory pointer by an uninitialized pointer invokes undefined behaviour. Either allocate enough memory:
pointers = malloc(256);
if(!pointers)
perror("malloc");
else
scanf("%255s", pointers);
Or declare it as a static array:
char pointers[256];
You should also consider using fgets() instead of scanf().
You may want to read i you are interested in fgets():
Difference between scanf() and fgets()
char *pointers; creates a pointer variable.
pointers is the address pointed to by pointers, which is indeterminate by
default.
*pointers is the data in the address pointed to by pointers, which you cannot do until address is assigned.
Just do this.
char arrays[12];
char *pointers;
pointers = arrays;
scanf("%s",pointers);
pointers is being used without initialisation, like int x; printf("%d\n", x);. You need to make your pointer point to something before using it. Which book are you reading?
pointers is an unitialized pointer. You are not able to write into it. You shall allocate enough memory to store a string, as you did with arrays. With a pointer, it is possible to use dynamic allocation (cf. malloc).
Could you elaborate on the error, i'm not around a compiler right now.
But for scanf and printf to work you must have this at the top of your program:
#include <stdio.h>
#include <stdlib.h>
Both are standard libraries for C. IO contains scanf, I'm fairly sure printf is in the same. But until you know which libraries you need for which functions it doesn't hurt to include both standard libraries for every program. Try to use custom header files as well so you don't need mass #includes for every file.
Don't forget malloc statements for memory allocation.
But I'm unsure what you're attempting to do with your code, please elaborate?

C - scanf() and then getenv()

I'm asking the user which environment variable he want to know and then I scan it with scanf. But it doesnt work for me. Here is my code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
char *value;
char input;
printf("Which variable do you want?\n");
scanf("%s", input);
value = getenv(input);
printf("%s", value);
}
The compiler says:
"Function argument assignment between types "const char*" and "char" ist not allowed"
So i tried to change the input variable to: char const *input
Now there is no compiler error, but when I submit a name, for example "USER", I get a "Segmentation fault (core dumped)" error.
The warning is because here
value = getenv(input);
you pass a char to getenv(), which has the prototype:
char *getenv(const char *name);
Define input as a char array like:
char input[256];
printf("Which variable do you want?\n");
scanf("%255s", input); //specify the width to avoid buffer overflow
Or, you can use dynamically memory allocation (using malloc) if you think 256 is not big enough for your purposes.
When you defined char *input; you satisfy the compiler because your syntax is valid: when calling scanf("%s", input); you are saying you want a string and it should get placed wherever input is.
The problem is input isn't anywhere (initialized) yet... where it points is undefined at the moment; before using any pointer you must make it point somewhere that is valid (and large enough to hold whatever you intend to put there).
There are a few ways you can solve this, but perhaps the easiest is to decide how large the input needs to be and declare a character array, such as: char input[512];. Be aware that this is problematic because if the input exceeds your buffer you will overwrite other memory... but this should get you moving forward for now.
char is a single char.
char *input declares a variable which hold a pointer to a character, but there is no memory for the data. In C, this is a correct behavior. However, sscanf expects that you actually pass a pointer which points to allocated memory (please consider that the function does not return any pointer, so it has no chance of allocating memory for you).
So between declaration and use, please use malloc to allocate memory.

Malloc array of characters dynamic vs static C

So I'm basically trying to take an input of scanf of letters (no spacing between them), place each letter into an array and spit out the corresponding letter to the array by using dynamically allocated arrays (malloc).
Crashes
#include <stdio.h>
#include <stdlib.h>
int main () {
char *userInput = malloc(sizeof(char)*3); /* dynamic */
scanf("%s", &userInput);
printf("user inputed %c", userInput[1]);
free(userInput);
return 0;
}
Runs
#include <stdio.h>
#include <stdlib.h>
int main () {
char userInput [3]; /* array */
scanf("%s", &userInput);
printf("user inputed %c", userInput[1]);
return 0;
}
Input:
asd
Output:
s
My understanding of dynamically allocated arrays was that char userInput [3]; is equivalent to char *userInput = malloc(sizeof(char)*3); but apparently from this case that isn't true? Anyone care to explain/help?
Welcome to Stack Overflow! Coincidentally, the main problem with your code is that it is vulnerable to a stack overflow. scanf has no way of knowing how big userInput is, because you didn't tell it, and will happily continue filling memory long past the end of your very short array.
If you want to capture exactly three characters (with no nul terminator), use scanf("%3c", userInput) instead. Note that without the NUL, you must not expect to treat userInput as a string; printing it via printf for example will result in a random amount of gibberish owing to the fact that C does not know where the string ended.
Now, to answer your actual question on "what's the difference between malloc and the static array": the difference is of scope. If you only ever use userInput before its creating function returns, there is no practical difference, but you're in trouble the minute you try to do something like this:
int function1 {
char my_string[3];
scanf("%3c", my_string);
return my_string; /* WRONG! DANGER! */
}
The return in the above example will happily return the pointer to my_string to the calling function. However, as soon as function1 returns, the stack is rolled back and the memory my_string occupied is essentially gone (and likely already re-used). The results are unpredictable but almost universally very bad for your program.
However, had you used malloc() instead, you could safely return the my_string pointer and the memory would persist until someone later called free(my_string) (where my_string is the pointer to the original my_string; it need not be named the same!).
This highlights another difference: with a stack variable such as char my_string[3];, you do not need to worry about (and indeed cannot) free() the memory, where as if the memory is malloc()'d instead, you must free() it if you wish to reclaim the memory.
There are some nuances to the above, such as file-scoped variables and static function variables, which I leave as topics for further reading.
As pointed in Giorgi's answer, the main problem is the incorrect usage of the address-of operator &.
However, the reason why it worked on one case and why it didn't work on another is very interesting.
char array[3]: When you declare that array, memory space will be allocated for it and array will be a label to that location(memory address). When you pass array to scanf (or use it anywhere else without subscripting []), you're passing an address to that function. Because of that, when you use the & operator on the label array, it returns the same address to you BUT with different type (T(*)[3]), which your compiler probably complained about. But, as the memory address is valid, it worked as expected.
char *array = malloc(): When you declare that variable, memory is also reserve for it, but this time in a different place and the space reserved is sizeof T(*), so it can hold a memory address. This variable also has an address in memory, which you can also get using &array. Then you malloc some memory and malloc returns to you an address of a memory block which you can now use. You can get that memory address by simply doing array. So, when you call scanf with the &array you're passing the variable address instead of the block address. That's why it crashes (I'm guessing you were not entering only two characters).
Check this code:
#include <stdio.h>
#include <stdio.h>
int main(void)
{
char *array[3];
char *ptr = malloc(3 * sizeof(char));
printf ("array : %p\n", array);
printf ("&array: %p\n\n", &array);
printf ("ptr : %p\n", ptr);
printf ("&ptr : %p\n", &ptr);
scanf("%s", &ptr);
printf ("ptr : %p\n", ptr);
return 0;
}
Which outputs:
$ ./draft
array : 0x7ffe2ad05ca0
&array: 0x7ffe2ad05ca0
ptr : 0x19a4010
&ptr : 0x7ffe2ad05c98
ABCD
ptr : 0x44434241
scanf got the address of the pointer, so when it saves the value it reads from stdin, it overwrites the address we had from malloc! The memory block we had is now gone, memory is leaking... Now, this is bad because we're overwriting stuff on our stack, memory is leaking, and it will crash.
Observe the last output: the value of ptr (which previously was the address of an allocated block) is now 0x44434241 (DCBA, ASCII Table)! How nice is that?

How to print elements by use of Pointers

Greetings,
I had been studying C++ for a while now.
I'm getting in to pointers now.
But I'm creating a program on C++ that will ask for a string("%s") input.
And I want to display its character on a different line.
But when I run the program I get the wrong letters.
Here's my code;
#include<stdio.h>
#include<stdlib.h>
main() {
char* name;
name = (char *)malloc(sizeof(char));
printf("Enter string: "); scanf("%s", name);
while(*name != '\0') {
printf("%c", name); *name++
}
}
Your reply is highly appreciated.
malloc(sizeof(char)) allocates space for a single character. This is probably not what you want. As the comments below point out, the dereferencing in *name++ is pointless. It does no harm, but perhaps indicates that you're thinking incorrectly about something. name++ has the same effect.
First, if you are going to study C++, you should learn to write C++ programs, not C programs. Here is your program in idiomatic C++:
#include <iostream>
#include <string>
int main(int, char **) {
std::string name;
std::cout << "Enter string: " << std::flush;
std::cin >> name;
std::cout << name << "\n";
}
One advantage of using C++ and its standard libraries over C and its standard libraries is precisely this: you almost never need to use pointers.
But, taking your program for what it is worth, there are sevearal problems. First, in C++, if you want to access the C header files, you should include them with their C++ names:
#include <cstdio>
#include <cstdlib>
Next, main requires a proper signature:
int main(int, char**) {
Most crucially, you are not allocating enough space for your user's name:
name = (char *)malloc(A_BIG_ENOUGH_NUMBER);
Here, you must allocate enough space that scanf() will not write beyond the end of your buffer. But, you can't possibly know how big that is until afte scanf runs. This catch-22 is the source of "buffer-overflow" bugs. For your test program, since you control the input, it is probably OK to just pick a number bigger than any name you'll ever type. In production code, you must NEVER, EVER, used scanf in this way.
name = (char *)mallocc(40);
By the way, if you are compiling this as C code, you should never cast the return from malloc. If you are compiling this as C++ code, you must always cast the return from malloc.
printf("%c", *name); name++
This line is missing a semicolon. Did you compile this program? In future, please only post code that you have compiled. Please use your computer's cut-and-paste features to post your code, never retype the code by hand.
This line has two other problems. First, you must derefence the name pointer to access the data to which it points. (So, *name instead of name.) Second, you need not dereference name in the second statement on this line, since you do nothing with the resulting pointed-to data. (So, name++ instead of *name++.)
Finally, and most importantly, buy, read, and learn from a good book.
Your program is likely printing junk because you only allocate one byte to your string buffer. When the user enters a string, you will have undefined behavior because the scanf will write past the end of name.
You need to alloc name like this:
char *name = (char *)malloc(MAX_STRING_SIZE, sizeof(char));
Even better to use calloc instead of malloc. Define MAX_STRING_SIZE however you like. A reasonable size depends on the application. In your case, if the users will be entering short strings, then perhaps a reasonable buffer size is 64 bytes, or perhaps 80 or 100.
Also, in your while loop, you can increment and dereference your pointer in one step, like this:
printf("%c", *name++);
If you don't like to be that terse, then you can break them apart, but you don't need to dereference the pointer to increment it.
printf("%c", *name); name++;
That's not C++, it's C.
malloc(sizeof(char)) will allocate storage of one char, I expect you wanted more than that.
Also there is no need to allocate dynamically here. Try:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char name[256];
char *p = name;
printf("Enter string: ");
scanf("%s", name);
while (*p != '\0') {
printf("%c", *p);
p++;
}
return 0;
}

Resources