After using malloc, name gets printed but after allocating memory and typing in a string, puts doesn't print the string at all, neither does printf...why is this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *name;
int size;
printf("enter the size if name below\n");
scanf("%d", &size);
name =(char*) malloc(size * sizeof(char));//since my compiler returns pointr of type void, you have specify whether (int*) or (char*)
if (name== NULL)
printf("memory allocation failed,,,\n");
printf("%s\n",name);
printf("enter name below\n");
scanf("%s", name);
printf("name is\n%s", name);
name = (char*)realloc(name, 100*sizeof(char));
if (name == NULL)
printf("failed\n");
gets(name);
getchar();
puts(name);
free(name);
return 0;
}
First things first, malloc/realloc do not return void, they return void* which is perfectly capable of being implicitly cast to any other pointer type. It's a bad idea to do so explicitly in C since it can hide certain subtle errors.
In addition, sizeof(char) is always one, you do not need to multiply by it.
Thirdly, using gets is a very bad idea since there's no way to protect against buffer overflow. There are much better ways to do user input.
As to the specific problem, I suspect it's most likely still sitting around at the getchar. gets will get a line from the user (including the newline character) but, unless you enter another character (probably a full line if it's using line-based I/O), it will seem to hang. Check this by simply hitting ENTER again after you've entered the name.
Try either fgets() or scanf() at the place of gets().It will work
The program that you have posted causes undefined behavior. This is because of
printf("%s\n",name);
There is nothing in the variable name and you are trying to print the value in the allocated memory. First you need to assign some value to name before printing it.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Can someone help me with this issue? For some reason, no matter what I try, doing printf isn't printing in my code. I've been trying to use the flush method, but that seems to just cause other issues. Is there anything else I can do?
int main(void) {
char **line;
size_t bufsize=MAXBUF;
printf("Type your name: ");
getline(&line,&bufsize,stdin);
}
You are trying to pass in an empty pointer, this pointer isn't pointing to any meaningful address at the start of the program. So the problem with this is that even if you were successful, it would overwrite some random address in memory with the input, and this is almost certainly what you don't want as it will cause a segmentation fault or a crash.
However that's not the reason why it's not compiling. It's not compiling because you are trying to pass in char *** to a function that expects char **.
So what I would do is:
#include <stdio.h>
int main(void) {
char *line=NULL;
size_t bufsize=0;
printf("Type your name: ");
if(getline(&line,&bufsize,stdin)==-1){
puts("Error: User cancelled input.");
}
else{
printf("Entered: %s",line);
}
free(line);
return 0;
}
So what this code does is that it creates a pointer to an array of characters but it sets the pointer to point to NULL so that the program can see it's not pointing anywhere, and then its address (&line) is given to the getline function, this turns the char * type into a char ** which is required by the getline function. Whenever you put a & in front of something in C, it adds an extra * to the type.
You probably know this already, but if a function states that it returns something, you should always return something, even if it's nonsense otherwise depending on the type that should be returned, that can sometimes cause a crash.
There was nothing wrong with your use of printf, that was fine. printf doesn't necessarily fflush to stdout, often the \n character will trigger a flush, but it's implementation specific, so if your program crashes before an fflush is written to stdout, then you may never see the last printf. You can try an fflush(stdout); before the getline function, but after the getline function may not work because it may crash before then.
In your case what's happening is that before the printf writes to the screen the getline takes in the address of the pointer (or pointer to a pointer), dereferences it to a pointer, isn't able to, so before you have a chance to enter in any keystrokes it crashes, losing the stdout pipe, so you end up never seeing your prompt.
When i run the altered code, above, i get:
XXXX#dell:~$ gcc Deleteme.c
XXXX#dell:~$ ./a.out
Type your name: test1
Entered: test1
XXXX#dell:~$
And it runs correctly under Linux. The key lesson in all this is that, terminals are slow to update on the screen, so some time in the past, the decision was made to separate out the functionality of printf.
There are two components to printf:
The part that writes the text to stdout.
The part that updates the terminal with stdout (the flush).
This question is interesting because 1) succeeded, but the system crashed before 2) was completed.
The documentation for getline says the first parameter must be a char **, but you pass it the address of line. Since line is a char **, &line is a char ***, which is the wrong type.
getline() allocates and re-allocates memory. The address of the length and the buffer need to reflect that.
int main(void) {
char *line = NULL;
size_t bufsize = 0;
printf("Type your name: ");
fflush(stdout); // Flush output before reading.
ssize_t len = getline(&line, &bufsize, stdin);
if (len < 0) Handle_error_with_code();
...
free(line); // When done, free memory
}
There is no need to allocate any memory before calling getline().
getline() expects line, bufsize to reflect allocated data via malloc() and friends. It is easy enough to start with NULL, 0 here.
First you are passing the address of line to the getline(), the documentation says that the first argument is the address of the first character position where the input string will be stored. It’s not the base address of the buffer, but of the first character in the buffer.
This pointer type (a pointer-pointer or the ** thing) causes massive confusion.
second your line pointer does not point to anything this should fix it:
char *line = (char *)malloc(bufsize * sizeof(char));
now line is pointing to valid memory address which we requested via malloc() function.
In Xcode I declared a string called myString with 5 spaces in memory.
int main() {
char myString[5];
printf("Insert a string: ");
scanf("%s", myString);
printf("Your string is %s.", myString);
return 0;
}
The problem is that whenever I type a word longer than 4 characters the console still prints out with printf() my string instead of complaining about it.
What is this due to?
In your case, as you've defined myString to have 5 chars, any input running longer than 4 chars (consider terminating null also as the 5th) will actually cause out of bound memory access, which produces undefined behavior. The result can be anything, inducing working normally, as if you had allocated enough memory.
You should be limiting your input using
scanf("%4s", myString);
and likewise.
Also, as a note, the recommended signature for main() is int main(int argc, char *argv[]) or at least, int main(void).
C will happily clobber any memory you hand it. AKA, a buffer overflow. :-)
My compiler (clang) shows this message:
11:17:warning: format specifies type 'char *' but the argument has
type 'char (*)[0]' [-Wformat]
scanf("%s", &name);
~~ ^~~~~
1 warning generated.
from the following code (greetings program):
/*
* Program: gretting2.c
* Utility: Display a greeting with your name.
* Author: Adrián Garro.
*/
#include <stdio.h>
int main () {
char name[0];
printf("-------------------\n");
printf("Write your name: \n");
printf("-------------------\n");
scanf("%s", &name);
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
}
What is actually going on, and how can I fix it?
In order to understand this, you have to understand what scanf is doing. scanf in this case is reading a string from stdin, and placing it into a buffer that you give it. It does not allocate that space for you, or detect overflow. You need to allocate sufficient space for your string. As it stands now, you are allocating zero space for your string, so everything is an overflow. This is a major bug.
Say instead of char[0], you did char[40], as another user suggests.What if the user of your program writes more than 40 characters? This results in undefined behavior. Essentially, it will write to memory you don't want it to write to. It might cause a segfault, it might result in crucial memory getting overwritten, or it might happen to work. This is a weakness of scanf. Look into fgets. You tell it the size of your buffer, and input will be truncated to fit.
Of course, that has nothing to do with your warning. You're getting a warning because referring to the name of an array is the same as referring to a pointer to its first element, i.e. name <==> &(name[0]). Taking a pointer to this is like taking a pointer to a pointer, i.e. &name <==> &&(name[0]). Since scanf is looking for an argument of type char*, and it's getting a pointer to that, the type checker complains.
Your code exhibits "undefined behavior." This means anything could happen. Anything.
You are passing a zero-length array to scanf(). Also, you are not passing the array length in the format string. This results in a buffer overflow vulnerability (always, in the case of a zero-length target array).
You need something like this:
char name[51];
scanf("%50s", name);
Note the %50s now specifies the size of the target array (less one, to leave room for the null terminator!), which avoids buffer overflow. You still need to check the return value of scanf(), and whether the input name is actually too long (you wouldn't want to truncate the user's input without telling them).
If you're on Linux, check out the tool called valgrind. It is a runtime memory error detector (among other things), and can sometimes catch errors like this for you (and much less obvious ones, which is the main point). It's indispensable for many C programmers.
Just change this:
scanf("%s", &name);
to:
scanf("%39s", name);
and this:
char name[0];
to:
char name[40];
Also to you have to end it with a '\0' with:
name[39] = '\0';
Depending on how robust you want this to be you will want to reconsider the approach. I guess the first thing is whether you understand the type you are using when declaring char name[ 0 ]. this is a 'zero-sized' array of byte-sized characters. This is a confusing thing and it wouldn't surprise me if its behaviour differs across compilers...
The actual warning being complained by the compiler is that the type doesn't match. If you take the address of the first character in the array you can get rid of that (i.e. use &( name[ 0 ] ) in the scanf call). The address of name is its location on the stack - it just so happens that the array implementation uses that same location to store the array data, and name is treated differently by the compiler when used on its own so that the address of an array is the same as the address of its first element...
Using char name[ 0 ] leaves you open to causing memory corruption because there is nowhere for the string to be read, and implementation details may just luck out and allow this to work. One simple way to fix this is to replace 0 with a meaningful number which you take to the maximum length of the input string. Say 32 so that you have char name[ 32 ] instead... however this doesn't handle the case of an even longer string.
Since we live in a world of lots of memory and large stacks you can probably do char name[ 4096 ] and use 4KB of memory for the buffer and that will be absolutely fine for real world usage.
Now... if you want to be a little anal and handle pathological cases, like a user leaning on some keys whilst asleep for hours before pressing enter and adding some enormous 8000 character long string there are a few ways to handle that too with 'dynamic memory allocation', but that might be a bit beyond the scope of this answer.
As an aside, from what I understand char foo[ 0 ] is intentionally valid - it may have originated as a hack and has a confusing type, but is not uncommonly relied on for an old trick to create variable sized structs as described in this page from the GCC online docs
char name[0]; ---> char name[100];
/* You need to allocate some memory to store the name */
2.scanf("%s", &name);----> scanf("%s", name);
/* scanf takes char* as an argument so you need to pass string name only. */
i don't think that scanf("%(length - 1)s", name); is needed.
Because %s is used to reads a string. This will stop on the first whitespace character reached, or at the specified field width (e.g. "%39s"), whichever comes first.
except these don't tend to be used as often. You, of course, may use them as often as you wish!
/
*
* Program: gretting2.c
* Utility: Display a greeting with your name.
* Author: Adrián Garro.
*/
#include <stdio.h>
int main () {
char name[100];
printf("-------------------\n");
printf("Write your name: \n");
printf("-------------------\n");
scanf("%s", name);
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
}
Because the correct way is
scanf("%s", name);
/* ^ no ampersand
and what is
char name[0];
you should specify a non-zero length and use it for scanf length specifier
scanf("%(length - 1)s", name);
/* ^ sunstitite with the value */
there were several problems with the OPs posted code
the following fixes most of them
I includd comments to indicate where the problems are
int main ()
{
//char name[0]; // this did not allow any room for the name
char name[100] = {'\0'}; // declare a 100 byte buffer and init to all '\0'
printf("-------------------\n");
printf("Write your name:, max 99 char \n"); // 99 allows room for nul termination byte
printf("-------------------\n");
//scanf("%s", &name); // this has no limit on length of input string so can overrun buffer
if( 1 == scanf("%99s", name) ) // 1) always check returned value from I/O functions
// 2) no '&' before 'name' because
// arrays degrade to pointer to array when variable
// name is used
// 3) placed max size limit on format conversion string
// so input buffer 'name' cannot be overflowed
{ // then scanf failed
perror( "scanf failed for name" );
return(-1); // indicate error
}
// implied else, scanf successful
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
return(0); // indicate success
} // end function: main
You are reading a "string", thus the correct way is:
scanf("%s", name);
Why does the compiler complain? When you provide an argument in scanf, you provide the memory location of the variable. For example:
int x;
scanf("%d", &x);
&x is int *, i.e., a pointer to an integer, so x will get the correct value.
When you read a string, you're actually reading many char variables together. To store them, you need a char * array; well, name is char * on its own, so no need to write &name. The latter is char **, i.e., a 2-dimensional array of char.
By the way, you also need to allocate space for the characters to read. Thus, you have to write char name[20] (or any other number). You also need to provide a return 0; in your int main().
My compiler (clang) shows this message:
11:17:warning: format specifies type 'char *' but the argument has
type 'char (*)[0]' [-Wformat]
scanf("%s", &name);
~~ ^~~~~
1 warning generated.
from the following code (greetings program):
/*
* Program: gretting2.c
* Utility: Display a greeting with your name.
* Author: Adrián Garro.
*/
#include <stdio.h>
int main () {
char name[0];
printf("-------------------\n");
printf("Write your name: \n");
printf("-------------------\n");
scanf("%s", &name);
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
}
What is actually going on, and how can I fix it?
In order to understand this, you have to understand what scanf is doing. scanf in this case is reading a string from stdin, and placing it into a buffer that you give it. It does not allocate that space for you, or detect overflow. You need to allocate sufficient space for your string. As it stands now, you are allocating zero space for your string, so everything is an overflow. This is a major bug.
Say instead of char[0], you did char[40], as another user suggests.What if the user of your program writes more than 40 characters? This results in undefined behavior. Essentially, it will write to memory you don't want it to write to. It might cause a segfault, it might result in crucial memory getting overwritten, or it might happen to work. This is a weakness of scanf. Look into fgets. You tell it the size of your buffer, and input will be truncated to fit.
Of course, that has nothing to do with your warning. You're getting a warning because referring to the name of an array is the same as referring to a pointer to its first element, i.e. name <==> &(name[0]). Taking a pointer to this is like taking a pointer to a pointer, i.e. &name <==> &&(name[0]). Since scanf is looking for an argument of type char*, and it's getting a pointer to that, the type checker complains.
Your code exhibits "undefined behavior." This means anything could happen. Anything.
You are passing a zero-length array to scanf(). Also, you are not passing the array length in the format string. This results in a buffer overflow vulnerability (always, in the case of a zero-length target array).
You need something like this:
char name[51];
scanf("%50s", name);
Note the %50s now specifies the size of the target array (less one, to leave room for the null terminator!), which avoids buffer overflow. You still need to check the return value of scanf(), and whether the input name is actually too long (you wouldn't want to truncate the user's input without telling them).
If you're on Linux, check out the tool called valgrind. It is a runtime memory error detector (among other things), and can sometimes catch errors like this for you (and much less obvious ones, which is the main point). It's indispensable for many C programmers.
Just change this:
scanf("%s", &name);
to:
scanf("%39s", name);
and this:
char name[0];
to:
char name[40];
Also to you have to end it with a '\0' with:
name[39] = '\0';
Depending on how robust you want this to be you will want to reconsider the approach. I guess the first thing is whether you understand the type you are using when declaring char name[ 0 ]. this is a 'zero-sized' array of byte-sized characters. This is a confusing thing and it wouldn't surprise me if its behaviour differs across compilers...
The actual warning being complained by the compiler is that the type doesn't match. If you take the address of the first character in the array you can get rid of that (i.e. use &( name[ 0 ] ) in the scanf call). The address of name is its location on the stack - it just so happens that the array implementation uses that same location to store the array data, and name is treated differently by the compiler when used on its own so that the address of an array is the same as the address of its first element...
Using char name[ 0 ] leaves you open to causing memory corruption because there is nowhere for the string to be read, and implementation details may just luck out and allow this to work. One simple way to fix this is to replace 0 with a meaningful number which you take to the maximum length of the input string. Say 32 so that you have char name[ 32 ] instead... however this doesn't handle the case of an even longer string.
Since we live in a world of lots of memory and large stacks you can probably do char name[ 4096 ] and use 4KB of memory for the buffer and that will be absolutely fine for real world usage.
Now... if you want to be a little anal and handle pathological cases, like a user leaning on some keys whilst asleep for hours before pressing enter and adding some enormous 8000 character long string there are a few ways to handle that too with 'dynamic memory allocation', but that might be a bit beyond the scope of this answer.
As an aside, from what I understand char foo[ 0 ] is intentionally valid - it may have originated as a hack and has a confusing type, but is not uncommonly relied on for an old trick to create variable sized structs as described in this page from the GCC online docs
char name[0]; ---> char name[100];
/* You need to allocate some memory to store the name */
2.scanf("%s", &name);----> scanf("%s", name);
/* scanf takes char* as an argument so you need to pass string name only. */
i don't think that scanf("%(length - 1)s", name); is needed.
Because %s is used to reads a string. This will stop on the first whitespace character reached, or at the specified field width (e.g. "%39s"), whichever comes first.
except these don't tend to be used as often. You, of course, may use them as often as you wish!
/
*
* Program: gretting2.c
* Utility: Display a greeting with your name.
* Author: Adrián Garro.
*/
#include <stdio.h>
int main () {
char name[100];
printf("-------------------\n");
printf("Write your name: \n");
printf("-------------------\n");
scanf("%s", name);
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
}
Because the correct way is
scanf("%s", name);
/* ^ no ampersand
and what is
char name[0];
you should specify a non-zero length and use it for scanf length specifier
scanf("%(length - 1)s", name);
/* ^ sunstitite with the value */
there were several problems with the OPs posted code
the following fixes most of them
I includd comments to indicate where the problems are
int main ()
{
//char name[0]; // this did not allow any room for the name
char name[100] = {'\0'}; // declare a 100 byte buffer and init to all '\0'
printf("-------------------\n");
printf("Write your name:, max 99 char \n"); // 99 allows room for nul termination byte
printf("-------------------\n");
//scanf("%s", &name); // this has no limit on length of input string so can overrun buffer
if( 1 == scanf("%99s", name) ) // 1) always check returned value from I/O functions
// 2) no '&' before 'name' because
// arrays degrade to pointer to array when variable
// name is used
// 3) placed max size limit on format conversion string
// so input buffer 'name' cannot be overflowed
{ // then scanf failed
perror( "scanf failed for name" );
return(-1); // indicate error
}
// implied else, scanf successful
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
return(0); // indicate success
} // end function: main
You are reading a "string", thus the correct way is:
scanf("%s", name);
Why does the compiler complain? When you provide an argument in scanf, you provide the memory location of the variable. For example:
int x;
scanf("%d", &x);
&x is int *, i.e., a pointer to an integer, so x will get the correct value.
When you read a string, you're actually reading many char variables together. To store them, you need a char * array; well, name is char * on its own, so no need to write &name. The latter is char **, i.e., a 2-dimensional array of char.
By the way, you also need to allocate space for the characters to read. Thus, you have to write char name[20] (or any other number). You also need to provide a return 0; in your int main().
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;
}