From what I heard, I should allocate the memory like this in line 14:
array[i]=malloc(sizeof(char)*(strlen(buffer)+1)); I haven't added the 1 and still the code works perfect. I cant make it crash of return anything than 0. So, is the +1 needed or not? And if it is, what are the consequences going to be since my program runs smoothly?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 5
#define SIZE 512
int main(){
char *array[N];
char buffer[SIZE];
int i,j;
for(i=0;i<N;i++){
printf("Give word no.%d",i+1);
gets(buffer);
array[i]=malloc(sizeof(char)*strlen(buffer));
printf("%d",strlen(buffer));
if(!array[i]){
printf("Program will now exit.");
exit(0);
};
strcpy(array[i],buffer);
}
Tried it with both +1 and without. Same results although I've seen in tutorials that it is needed.
The +1 is needed to allocate room for the null terminator. If you don't, then you might write to the allocated array out of bounds, which is undefined behavior. What is undefined behavior and how does it work? Meaning it might seem to work just fine, to break mysteriously later on.
sizeof(char) is by definition always 1 though, so that part is not needed.
Recommendation: Use array[i] = malloc(strlen(buffer) + 1);
As a side note, whoever (book/teacher) told you to use gets should be retired and not be used as a source of learning C programming. Why is the gets function so dangerous that it should not be used?
Related
This question already has answers here:
Accessing an array out of bounds gives no error, why?
(18 answers)
Closed 2 years ago.
Usually, this question is probably phrased in a positive way, becoming the next member in the club of duplicate questions - this one hopefully isn't. I have written a simple program to reverse a string in C. Here it is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char arr[4] = "TEST";
char rev[2];
int j = 0;
for(int i = 0; i < 4; i++) {
j = 4 - i - 1;
rev[j] = arr[i];
}
printf("%s\n",rev);
}
When I define char arr and char rev to be of size 4, everything works fine. When I leave arr size out I get unexpected repeat output like "TSTTST". When I define rev to be an array of 2 chars, I do not get a segfault, yet in the loop I am trying to access its third and fourth element. As far as my relatively limited understanding tells me, accessing the third element in an array of length two should segfault, right? So why doesn't it?
EDIT:
Interestingly enough, when I leave the loop out like so
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char arr[4] = "TEST";
char rev[2] = "00";
printf("%s\n",rev);
}
it prints "00TEST". What happened here? Some kind of overflow? I even restarted the terminal, recompiled and ran again.
EDIT 2:
I have been made aware that this is indeed a duplicate. However, most of the suggested duplicates referred to C++, which this isn't. I think this is a good question for new C programmers to learn about and understand undefined behavior. I, for one, didn't know that accessing an array out of bounds does not always cause a SEGFAULT. Also, I learned that I have to terminate string literals myself, which I falsely believed was done automatically. This is partly wrong: it is added automatically - the C99 Standard (TC3) says in 6.4.5 String literals that terminating nulls are added in translation phase 7. As per this answer and the answers for this question, char arrays are also null-terminated, but this is only safe if the array has the correct length (string length + 1 for null-terminator).
char rev[2] assigns a memory of size 2*sizeof(char) with variable/pointer rev. You are accessing memory not allocated to the pointer. It may or may not cause errors.
It might appear to work fine, but it isn't very safe at all. By writing data outside the allocated block of memory you are overwriting some data you shouldn't. This is one of the greatest causes of segfaults and other memory errors, and what you're observing with it appearing to work in this short program is what makes it so difficult to hunt down the root cause.
When you do rev[2] or rev[3] you are accessing rev + 2 and rev + 3 addresses which are not allocated to rev pointer. Since its a small program and there is nothing there, it's not causing any errors.
In respect to edit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char arr[4] = "TEST";
char rev[2] = "00";
printf("%s\n",rev);
}
%s prints till null is encountered, the size you have assigned of the arr and rev doesn't allow for null to be there, try changing values as follow:
char arr[5] = "TEST";
char rev[3] = "00";
The program will work as intended as in arr there will be TEST\0 and rev will be rev\0 where \0 is null character in C.
Give this article a read, it'll solve most of your queries.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void foo() {
char *a_heap_pointer;
a_heap_pointer = (char*)malloc(1 * sizeof(char));
strcpy(a_heap_pointer, "a");
printf("%s\n", a_heap_pointer);
while (1){
++a_heap_pointer;
a_heap_pointer = (char*)malloc(1 * sizeof(char));
strcpy(a_heap_pointer, "b");
printf("%s\n", a_heap_pointer);
}
}
int main (void) {
foo();
return 0;
}
Hi there, I'm trying to make my C program cause a segmentation fault by incrementing a pointer that points at the heap, by 1 byte, repeatedly, until the program crashes. However, as my code stands now it just runs indefinitely? I presume because the heap is so large that it would take awhile for it to run out. How can I make my program break the heap?
Printing on the screen is very slow compared to in-memory operations, so if you remove the printfs, you will probably not have to wait as long.
But modern computers have a lot of memory, and when you take into account swap space on disk it can be many hundreds of gigabytes. Prepare to wait for a long time.
Also, in C, strings are NUL-terminated, so the strings "a" and "b" both require two chars storage. Therefore your calls to strcpy overwrite memory that may be used for other things, so your program's behaviour is undefined. Anything can happen, for example that it gets stuck and never terminates.
And a side note: I'm not sure what effect you expect ++a_heap_pointer; to have? You increment that pointer, but then you immediately replace the incremented value by the return value from malloc, so the result of the increment operation will never be used.
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.
I wrote a code just to understand how fread works and I don't understand how this is possible. Here my code :
#include <stdio.h>
#include <stdlib.h>
void main(){
char spool[5] = "hello";
fread(spool, sizeof(char), 6, stdin); //stdin == "bonjour"
printf("\n%s\n", spool);
}
So first, I thought spool's value would be replaced by "bonjo" but I got "bonjou". I don't understand why I get a 6 characters string instead of a 5 characters string.
char spool[5] = "hello";
This is wrong, because strings in C are null terminated. You don't allocate space for the null termination. A decent compiler should give you a warning about this. (Apparently gcc does not even with -Wall -Wextra, so that kind of sucks).
Reading "bounjour" into that array is also wrong, because C arrays have no boundary checks, nor do any of the library functions. So if you try to store more data in the array than you have room, you will write outside the boundaries of the array and the program will (hopefully) crash. You invoke undefined behavior, so anything might happen.
Solve this by declaring a large enough array, and study null termination of strings.
You need to increase the size of the spool buffer, (it cannot store more than 5 chars, that leads to Undefined beahvior):
#include <stdio.h>
#include <stdlib.h>
int main(){
char spool[15] = "hello";
fread(spool, sizeof(char), 6, stdin); //stdin == "bonjour"
printf("\n%s\n", spool);
}
Output:
bonjou
What you have is undefined behavior. You are trying to read 6 characters into a array which can hold 5 characters.Please note that the array should be large enough to hold a nul terminator.
Increase the size of your array spool to hold required characters.
I tried to create one array of strings in C. Here is the code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main()
{
char *foo[100];
strcpy(foo[0], "Testing this");
printf("%s ", foo[0]);
return 1;
}
But when I compile it, it simply breaks. No error, no nothing, it simply doesn't work and breaks. Any suggestion? When I tri char *foo[10] it works, but I can't work with just 10 strings
You allocated an array of pointers but did not allocate any memory for them to point to. You need to call malloc to allocate memory from the heap.
char *foo[100];
foo[0] = malloc(13);
strcpy(foo[0], "Testing this");
Naturally you would need to free the memory at some later date when you were finished with it.
Your code invokes what is known as undefined behavior. Basically anything can happen, including the code working as you intended. If the version with char *foo[10] works as you intended that's simply down to luck.
As an aside, your main() definition is wrong. It should be int main(void).
You're assigning an unallocated pointer. char *foo[100] is an array of 100 unallocated pointers, and they point to unknown locations in memory, ones which you can probably not access.
You are creating an 100 pointers to point no where. As explained by David, you need to dynamically allocate the memory. However, you can also have the compiler do this for you if you know the size of the strings (or max):
// Create an array of 10 strings of size 100 and initialize them automatically
char foo[10][100] = {0};
// Now you can use it them and not worry about memory leaks
strcpy(foo[0], "text");
// Or use the safer version
strcpy_s(foo[0], 100, "text");
Expanding upon other people's answers:
char *foo;
is a pointer to a character. It may be assigned the address of a single character or assigned the address of the first of a sequence of characters terminated by '\0'. It may also be assigned an address via malloc().
char foo[100];
is space for 100 characters or space for a string of up to 99 characters and a terminating '\0' character.
char *foo[100];
is 100 character pointers, i.e., 100 char *foo; types.
#include <stdlib.h>
#include <stdio.h>
int main(void){
char *foo[100];
foo[0] = malloc(13*(sizeof(char)));
strcpy(foo[0], "Testing this");
printf("%s ", foo[0]);
return 0;
}
This is the corrected version of your code.
MISTAKE: not allocating enough memory for the string.
CORRECTION: using malloc to allocate 13 blocks of memory for the string.