I've written the following code :
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* ch = malloc(0 * sizeof(char));
int n = 300;
sprintf(ch, "%d", n);
printf("ch is : %s", ch);
return 0;
}
I've switched the 0 in the malloc function to different numbers to experiment and I tried putting 0 meaning allocating no memory but when I run the program it worked just fine and I don't understand why is that exactly because if I put 0 it's like allocating no memory at all so what's happening here ?
C lets you shoot yourself in the foot.
The malloc docs say
If size is zero, the return value depends on the particular library
implementation (it may or may not be a null pointer), but the returned
pointer shall not be dereferenced.
So your implementation is returning something other than zero. Your sprintf is writing into memory that it "shall not" write to. But in this particular case, you got lucky, and it was nowhere critical - at least nowhere that mattered in this short test program. In a longer program with more mallocs and frees, you almost surely would run into trouble.
malloc(0) is implementation-defined. It may return a null pointer, see C FAQ for detail.
The problem is in the following line:
printf("ch is : %s", ch);
ch is not a string (i.e, null-terminated char array), to print it with "%s" is illegal.
Related
so I'm quite new in this, sorry if it sound like a dumb question
I'm trying to understand malloc, and create a very simple program which will print "ABC" using ASCII code
here is my code (what our professor taught us) so far
char *i;
i = malloc(sizeof(char)*4);
*i = 65;
*(i+1) = 66;
*(i+2) = 67;
*(i+3) = '\0';
what I don't understand is, why do I have to put malloc there?
the professor told us the program won't run without the malloc,
but when I tried and run it without the malloc, the program run just fine.
so what's the function of malloc there?
am I even using it right?
any help and or explanation would be really appreciated
the professor told us the program won't run without the malloc
This is not quite true, the correct wording would be: "The program's behavior is undefined without malloc()".
The reason for this is that
char *i;
just declares a pointer to a char, but there's no initialization -- this pointer points to some indeterminate location. You could be just lucky in that writing values to this "random" location works and won't result in a crash. I'd personally call it unlucky because this hides a bug in your program. undefined behavior just means anything can happen, including a "correct" program execution.
malloc() will dynamically request some usable memory and return a pointer to that memory, so after the malloc(), you know i points to 4 bytes of memory you can use. If malloc() fails for some reason (no more memory available), it returns NULL -- your program should test for it before writing to *i.
All that said, of course the program CAN work without malloc(). You could just write
char i[4];
and i would be a local variable with room for 4 characters.
Final side note: sizeof(char) is defined to be 1, so you can just write i = malloc(4);.
Unfortunately, "runs fine" criterion proves nothing about a C program. Great deal of C programs that run to completion have undefined behavior, which does not happen to manifest itself on your particular platform.
You need special tools to see this error. For example, you can run your code through valgrind, and see it access uninitialized pointer.
As for the malloc, you do not have to use dynamic buffer in your code. It would be perfectly fine to allocate the buffer in automatic memory, like this:
char buf[4], *i = buf;
You have to allocate space for memory. In the example below, I did not allocate for memory for i, which resulted in a segmentation fault (you are trying to access memory that you don't have access to)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *i;
strcpy(i, "hello");
printf("%s\n", i);
return (0);
}
Output: Segmentation fault (core dumped)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *i;
/*Allocated 6 spots with sizeof char +1 for \0 character*/
i = malloc(sizeof(char) * 6);
strcpy(i, "hello");
printf("%s\n", i);
return (0);
}
Result: hello
Malloc allows you to create space, so you can write to a spot in memory. In the first example, "It won't work without malloc" because i is pointing to a spot in memory that doesn't have space allocated yet.
The C program is a Damereau-Levenshtein algorithm that uses a matrix to compare two strings. On the fourth line of main(), I want to malloc() the memory for the matrix (2d array). In testing, I malloc'd (0) and it still runs perfectly. It seems that whatever I put in malloc(), the program still works. Why is this?
I compiled the code with the "cl" command in the Visual Studio developer command prompt, and got no errors.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main(){
char y[] = "felkjfdsalkjfdsalkjfdsa;lkj";
char x[] = "lknewvds;lklkjgdsalk";
int xl = strlen(x);
int yl = strlen(y);
int** t = malloc(0);
int *data = t + yl + 1; //to fill the new arrays with pointers to arrays
for(int i=0;i<yl+1;i++){
t[i] = data + i * (xl+1); //fills array with pointer
}
for(int i=0;i<yl+1;i++){
for(int j=0;j<xl+1;j++){
t[i][j] = 0; //nulls the whole array
}
}
printf("%s", "\nDistance: ");
printf("%i", distance(y, x, t, xl, yl));
for(int i=0; i<yl+1;i++){
for(int j=0;j<xl+1;j++){
if(j==0){
printf("\n");
printf("%s", "| ");
}
printf("%i", t[i][j]);
printf("%s", " | ");
}
}
}
int distance(char* y, char* x, int** t, int xl, int yl){
int isSub;
for(int i=1; i<yl+1;i++){
t[i][0] = i;
}
for(int j=1; j<xl+1;j++){
t[0][j] = j;
}
for(int i=1; i<yl+1;i++){
for(int j=1; j<xl+1;j++){
if(*(y+(i-1)) == *(x+(j-1))){
isSub = 0;
}
else{
isSub = 1;
}
t[i][j] = minimum(t[i-1][j]+1, t[i][j-1]+1, t[i-1][j-1]+isSub); //kooks left, above, and diagonal topleft for minimum
if((*(y+(i-1)) == *(x+(i-2))) && (*(y+(i-2)) == *(x+(i-1)))){ //looks at neighbor characters, if equal
t[i][j] = minimum(t[i][j], t[i-2][j-2]+1, 9999999); //since minimum needs 3 args, i include a large number
}
}
}
return t[yl][xl];
}
int minimum(int a, int b, int c){
if(a < b){
if(a < c){
return a;
}
if(c < a){
return c;
}
return a;
}
if(b < a){
if(b < c){
return b;
}
if(c < b){
return c;
}
return b;
}
if(a==b){
if(a < c){
return a;
}
if(c < a){
return c;
}
}
}
Regarding malloc(0) part:
From the man page of malloc(),
The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
So, the returned pointer is either NULL or a pointer which can only be pasxed to free(), you cannot expect to dereference that pointer and store something into the memory location.
In either of the above cases, you're trying to to use a pointer which is invalid, it invokes undefined behavior.
Once a program hits UB, the output of that cannot be justified anyway.
One of the major outcome of UB is "working fine" (as "wrongly" expected), too.
That said, follwing the analogy
"you can allocate a zero-sized allocation, you just must not dereference it"
some of the memory debugger applications hints that usage of malloc(0) is potentially unsafe and red-zones the statements including a call to malloc(0).
Here's a nice reference related to the topic, if you're interested.
Regarding malloc(<any_size>) part:
In general, accessing out of bound memory is UB, again. If you happen to access outside the allocated memory region, you'll invoke UB anyways, and the result you speculate cannot be defined.
FWIW, C itself does not impose/ perform any boundary checking on it's own. So, you're not "restricted" (read as "compiler error") from accessing out of bound memory, but doing so invokes UB.
It seems that whatever I put in malloc(), the program still works. Why is this?
int** t = malloc(0);
int *data = t + yl + 1;
t + yl + 1 is undefined behavior (UB). Rest of code does not matter.
If t == NULL, adding 1 to it is UB as adding 1 to a null pointer is invalid pointer math.
If t != NULL, adding 1 to it is UB as adding 1 to that pointer is more than 1 beyond the allocating space.
With UB, the pointer math may worked as hope as typical malloc() allocates larges chunks, not necessarily the small size requested. It may crash on another platform/machine or another day or phase of the moon. The code is not reliable even if it works with light testing.
You just got lucky. C does not do rigorous bounds checking because it has a performance cost. Think of a C program as a raucous party happening in a private building, where the OS police are stationed outside. If somebody throws a rock that stays inside the club (an example of an invalid write that violates the ownership convention within the process but stays within the club boundaries) the police don't see it happening and take no action. But if the rock is thrown and it goes flying dangerously out the window (an example of a violation that is noticed by the operating system) the OS police step in and shut the party down.
The C standard says:
If the size of the space requested is zero, the behavior is implementation-defined; the value returned shall be either a null pointer or a unique pointer. [7.10.3]
So we have to check what your implementation says. The question says "Visual Studio," so let's check Visual C++'s page for malloc:
If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item.
So, with Visual C++, we know that you're going to get a valid pointer rather than a null pointer.
But it's just a pointer to a zero-length item, so there's not really anything safe you can do with that pointer except pass it to free. If you dereference the pointer, the code is allowed to do anything it wants. That's what's meant by "undefined behavior" in the language standards.
So why does it appear to work? Probably because malloc returned a pointer to at least a few bytes of valid memory since the easiest way for malloc to give you a valid pointer to a zero-length item is to pretend you really asked for at least one byte. And then the alignment rules would round that up to something like 8 bytes.
When you dereference the beginning of that allocation, you likely have some valid memory. What you're doing is strictly illegal, non-portable, but, with this implementation, likely to work. When you index farther into it, you'll likely start corrupting other data structures (or metadata) in the heap. If you index even father into it, you're increasingly likely to crash due to hitting an unmapped page.
Why does the standard allow malloc(0) to be implementation-defined instead of just requiring it to return a null pointer?
With pointers, it's sometimes hand to have special values. The most obvious being the null pointer. The null pointer is just a reserved address that will never be used for valid memory. But what if you wanted another special pointer value that had some meaning to your program?
In the dark days before the standard, some mallocs allowed you to effectively reserve additional special pointer values by calling malloc(0). They could have used malloc(1) or any other very small size, but malloc(0) made it clear that you just wanted to reserve and address rather than actual space. So there were many programs that depended on this behavior.
Meanwhile, there were programs that expected malloc(0) to return a null pointer, since that's what their library had always done. When the standards people looked at the existing code and how it used the library, they decided they couldn't choose one method over the other without "breaking" some of the code out there. So they allowed malloc's behavior to remain "implementation-defined."
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?
program in c language
void main()
{
char *a,*b;
a[0]='s';
a[1]='a';
a[2]='n';
a[3]='j';
a[4]='i';
a[5]='t';
printf("length of a %d/n", strlen(a));
b[0]='s';
b[1]='a';
b[2]='n';
b[3]='j';
b[4]='i';
b[5]='t';
b[6]='g';
printf("length of b %d\n", strlen(b));
}
here the output is :
length of a 6
length of b 12
Why and please explain it.
thanks in advance.
You are assigning to pointer (which contains garbage) without allocating memory. What you are noticing is Undefined Behavior. Also main should return an int. Also it does not make sense to try and find the length of an array of chars which are not nul terminated.
This is how you can go about:
Sample code
When you declare any variable it comes with whatever it had in memory previously where your application is running, and since pointers are essentially numbers, whatever number it had referenced to some random memory address.
Then, when setting a[i], the compiler interprets that as you want to step sizeof(a) bytes forward, thus, a[i] is equal to the address (a + i*1) (1 because chars use one byte).
Finally, C-strings need to be NULL terminated (\0, also known as sentinel), and methods like strlen go over the length of the string until hitting the sentinel, most likely, your memory had a stray 0 somewhere that caused strlen to stop.
Allocate some memory and terminate the strings then it will work better
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(){
char *a=malloc(10);
char *b=malloc(10);
if(a){
a[0]='s';
a[1]='a';
a[2]='n';
a[3]='j';
a[4]='i';
a[5]='t';
a[6]=(char)0;
printf("length of a %d\n", (int)strlen(a));
}else{
printf("Failed to allocate 10 bytes\n" );
}
if(b){
b[0]='s';
b[1]='a';
b[2]='n';
b[3]='j';
b[4]='i';
b[5]='t';
b[6]='g';
b[7]=(char)0;
printf("length of b %d\n", (int)strlen(b));
}else{
printf("Failed to allocate 10 bytes\n" );
}
free(a);
free(b);
}
Undefined behavior. That's all.
You're using an uninitialized pointer. After that, all bets are off as to what will happen.
Of course, we can attempt to explain why your particular implementation acts in a certain way but it'd be quite pointless outside of novelty.
The indexing operator is de-referencing the pointers a and b, but you never initialized those pointers to point at valid memory. Writing to un-initialized memory triggers undefined behavior.
You are simply "lucky" (or unlucky, it depends on your viewpoint) that the program doesn't crash, that the pointer values are such that you succeed in writing at those locations.
Note that you never write the termination character ('\0') to either string, but still get the "right" value from strlen(); this implies that a and b both point at memory that happens to be full of zeros. More luck.
This is a very broken program; that it manages to run "successfully" is because it's behavior is undefined, and undefined clearly includes "working as the programmer intended".
a and b are both char pointers. First of all, you didn't initialise them and secondly didn't terminate them with NULL.
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;
}