Hi I am quite new to C and I have a question about the behavior of array initialization using [] and malloc.
int main() {
int* pointer;
for(int i = 0; i < 100; i++) {
// Init the Array
int tmp[2] = {};
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
}
}
// expected 1 here, but got 99
printf("%d\n", pointer[1]);
return 0;
}
Why is the output 99? I thought the array is re-inited every loop, but it turns out using the same memory address. And if I use malloc to init the array instead, the result becomes 1 as expected.
Is there any way I could get result 1 without using malloc?
Your code is invalid as you access the variable which is out of the scope using the reference. It is undefined behaviour.
Every time you assign the i to the same element to the array. Pointer only references (points to) the first element of this array. So if you change the underlaying object the value you get using the reference will change as well. If your finger is pointing to the box of 5 apples and someone eats 2 apples, your finger will point to the box of 3 apples, not 5.
You need to make a copy of the object.
if(i == 1) {
pointer = malloc(sizeof(tmp));
memcpy(pointer, tmp, sizeof(tmp));
}
or break the loop (declaring it static or moving the tmp out of the for loop scope)
for(int i = 0; i < 100; i++) {
// Init the Array
static int tmp[2];
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
break;
}
}
The scope of the array tmp is the block scope of the for loop
for(int i = 0; i < 100; i++) {
// Init the Array
int tmp[2] = {};
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
}
}
That is in each iteration of the loop a new array tmp is created and ceases to be alive after exiting the block.
Thus the pointer pointer is invalid after the for loop. Dereferencing the pointer after the for loop invokes undefined behavior.
You have gotten the result 99 only because the array tmp was not being reallocated and the memory occupied by the array was not yet overwritten. So the last value stored in this extent of memory that is the value of i equal to 99 was outputted.
Even if you will declare the array tmp before the for loop then using the pointer pointer you will get as the output the value 99 that is the value last stored in the array.
You could write for example
int tmp[2] = { 0 };
int *pointer = tmp;
for(int i = 0; i < 100; i++) {
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
}
And the last value stored in the array (when i is equal to 99)
tmp[1] = i;
will be outputted in this call
printf("%d\n", pointer[1]);
Pay attention to that such an initialization with empty braces is invalid in C opposite to C++
int tmp[2] = {};
You need to write at least like
int tmp[2] = { 0 };
As we know pointer stores a memory address.
Here, I think when you give the command: pointer = tmp;,
the address of the array stored in 'tmp' is copied to the 'pointer'.
But when the loop of i = 1 gets completed, the array that you created in that particular loop and the pointer 'tmp' gets forgotten.
Then the loop for i=2 starts, 'tmp' and the array gets created again.
It happens again till the loop end.
I think that the program is storing tmp[1] at the same location every time due to which the data stored at that changes again and again.
So, when you give the command printf("%d\n", pointer[1]);, the data at that address get printed which is no longer equal to 1, it has changed.
The mistake is that we shared the address of 'tmp' with the 'pointer'.
But when we use malloc, we lock that memory means other programs can't use that memory. ( That's why we always need to free that memory to avoid memory leaks ).
It's the reason while using malloc you get output as 1 as your other commands can't touch that particular memory.
Solution:
If you want to solve the problem without malloc.
Initialise 'pointer' as an array to store data of 'tmp'.
use this code,
pointer[0] = tmp[0]; pointer[1] = tmp[1];
at place of
pointer = tmp;.
Now, you will not be copying addresses to 'pointer' but the data in the 'tmp'.
And if you have a big array with many values in it, just use it for loop.
solution image
Also, you will get the same problem if you do it like this, all because of copying only the address, you will be doing the same thing.
Maybe you can relate,same problem image
Thanks.
Related
I have to dynamically increase a length of double array. I know, how to do it with char array, so I tried this:
int main() {
char * tmp = NULL;
for (int i = 1; i <= 4; i++) {
tmp = realloc(tmp, i * sizeof(char));
tmp[i] = 'i';
}
puts("char OK");
double * tmp1 = NULL;
for (int i = 1; i <= 4; i++) {
tmp1 = realloc(tmp1, i * sizeof(double));
tmp1[i] = 0;
}
return 0;
}
The first array works fine. But the second one crushes with message realloc(): invalid next size.
These are my 2 questions:
Why this way doesn't work in a double array?
How to dynamically increase the size of array of doubles?
UPD:
removed a typo
TL;DR: Both the snippets are wrong, the first one appears to work because of undefined behavior.
To elaborate, the problem is with your indexing logic. C uses a 0-based indexing. So, inside the loop which is staring the iteration from value of i as 1, by using
tmp[i] = .......
you're trying to access invalid memory, at this point, only access up to tmp[i-1] is valid.
You need to use tmp1[i-1] = 0;, and likewise.
That said,
Always check for the success of the memory allocator functions before using the returned pointers.
Never use the form
pointer = realloc (pointer, ......)
because, in case realloc call fails, you'll end up losing the original pointer, too.
Quoting C11, chapter ยง7.22.3.5
The realloc function returns a pointer to the new object (which may have the same
value as a pointer to the old object), or a null pointer if the new object could not be
allocated.
and
[....] If memory for the new object cannot be
allocated, the old object is not deallocated and its value is unchanged.
Always use a temporary pointer variable to store the return value of realloc(),
check for the success of the call [not-null return value] and
then assign it back to the original variable, if needed.
I want to get numbers from the keyboard (or from a file: ./a.out < file) and store them in an array. The idea is that the length of the array is unknown.
#include <stdio.h>
#include <stdlib.h>
int* newElem(){
int* elm= malloc(sizeof(int));
if (elm == NULL) {
printf("\nError: memory allocation failed.\n");
exit(-1);
}
return elm;
}
int main(){
int *array,x,size,i=0;
while( scanf("%d",&x)==1 ){
array= newElem();
array[i]=x;
i++;
}
size=i;
free(array);
printf("size=%d",size);
return(0);
}
Why does this crash after I enter:
1 2 3 4 5 6 7 8
In your code
array= newElem();
is going to overwrite the existing pointer (memory) every time. so, array[i] becomes invalid, which essentially is an access out of bounds which in turn invokes undefined behavior. You need to use realloc() to re-size the allocated memory.
Simple.
array= newElem();
array[i]=x;
i++;
newElem() always return int[1] and you tried to access [n]
First you need to know that an array is a sequence of consecutive addresses.
This means that if the address of the first element is 0, the address of the second element will be 1, and the next 2, so on...
When you say x[10] in C, you are in fact saying *(x + 10), which means "from the first element (0), advance 10 addresses (+ 10), and give me the contents (* operator) of that address as an int.
So you see, there is a mathematical relation between elements, they are all next to each other in memory.
Now, to your code...
When you call array= newElem();, your pointer array points to the newly allocated address. However, any previous address array was pointing to before is lost, which is causing both your unexpected behavior and memory leak.
When you first call array= newElem(), lets suppose an integer is allocated at the address A, and the next time a new integer is allocated at the address B, and so on...
On first iteration, with i = 0:
while( scanf("%d",&x)==1 ){
array= newElem();
// array points to A
array[i]=x;
// array[0] = x
// or *(array + 0) = x
// same as *(array) = x
i++;
// i = 1
}
Now you will MOST LIKELY have an error (i = 1):
while( scanf("%d",&x)==1 ){
array= newElem();
// address A is lost, and now array points to B
array[i]=x;
// array[1] = x; -> likely an ERROR
// *(array + 1) = x
i++;
// i = 2
}
On the second iteration, you try to access the address NEXT TO the new address array points to, which would be C, that is why you get a violation.
Your code does not maintain a relationship between the elements of the array, you are essentially creating single integers in every iteration, and then trying
to access then but you are actually accessing invalid memory addresses.
It is not a very simple concept at first, comment if you need further clarification.
When I run print_puzzle(create_puzzle(input)), I get a bunch of gobbledegook at the bottom of the output, only in the last row. I have no idea why this keeps happening. The output is supposed to be 9 rows of 9 numbers (the input is a sudoku puzzle with zeroes representing empty spaces).
This bunch of code should take that input, make a 2d array of strings and then, with print_puzzle, print those strings out in a grid. They are string because eventually I will implement a way to display all the values the square could possibly be. But for now, when I print it out, things are screwed up. I even tried putting the null value in every single element of all 81 strings but it still get's screwed up when it goes to print the strings. I'm lost!
typedef struct square {
char vals[10]; // string of possible values
} square_t;
typedef struct puzzle {
square_t squares[9][9];
} puzzle_t;
static puzzle_t *create_puzzle(unsigned char vals[9][9]) {
puzzle_t puz;
puzzle_t *p = &puz;
int i, j, k, valnum;
for (i = 0; i < 9; i++) {
for (j = 0; j < 9; j++) {
puz.squares[i][j].vals[0] = '\0';
puz.squares[i][j].vals[1] = '\0';
puz.squares[i][j].vals[2] = '\0';
puz.squares[i][j].vals[3] = '\0';
puz.squares[i][j].vals[4] = '\0';
puz.squares[i][j].vals[5] = '\0';
puz.squares[i][j].vals[6] = '\0';
puz.squares[i][j].vals[7] = '\0';
puz.squares[i][j].vals[8] = '\0';
puz.squares[i][j].vals[9] = '\0';
valnum = vals[i][j] -'0';
for (k = 0; k < 10; k++){
if ((char)(k + '0') == (char)(valnum + '0')){
char tmpStr[2] = {(char)(valnum +'0'),'\0'};
strcat(puz.squares[i][j].vals, tmpStr);
}
}
}
}
return p;
}
void print_puzzle(puzzle_t *p) {
int i, j;
for (i=0; i<9; i++) {
for (j=0; j<9; j++) {
printf(" %2s", p->squares[i][j].vals);
}
printf("\n");
}
}
In short:
In function create_puzzle(), you are returning a pointer to the local variable puz. Local variables are only known to function inside their own. So the content referenced by the pointer returned by create_puzzle is indeterminate.
More details:
In C++, local variables are usually generated as storage on a "stack" data structure. when create_puzzle() method is entered, its local variables come alive. A function's local variables will be dead when the method is over. An implementation of C++ is not required to leave the garbage you left on the stack untouched so that you can access it's original content. C++ is not a safe language, implementations let you make mistake and get away with it. Other memory-safe languages solve this problem by restricting your power. For example in C# you can take the address of a local, but the language is cleverly designed so that it is impossible to use it after the lifetime of the local ends.
This answer is very awesome:
Can a local variable's memory be accessed outside its scope?
In function create_puzzle(), you are returning a pointer of the type puzzle_t. But, the address of variable puz of the type puzzle_t is invalid once you return from the function.
Variables that are declared inside a function are local variables. They can be used only by statements that are inside that function. These Local variables are not known to functions outside their own, so returning an address of a local variable doesn't make sense as when the function returns, the local storage it was using on the stack is considered invalid by the program, though it may not get cleared right away. Logically, the value at puz is indeterminate, and accessing it results in undefined behavior.
You can make puz a global variable, and use it the way you are doing right now.
You are returning a local variable here:
return p;
Declare p and puz outside of the function, then it should work.
p point to local memory that is unavailable after the function ends. Returning that leads to problems. Instead allocate memory.
// puzzle_t puz;
// puzzle_t *p = &puz;
puzzle_t *p = malloc(sizeof *p);
assert(p);
Be sure to free() the memory after the calling code completes using it.
I am reading from a file (each line wolds 1 word) and putting each line into an array. However I'll get a segmentation fault whenever I try to access any element in the array. Any help on this is greatly appreciated.
*update: added a while loop to grab the character one by one but I still get a segmentation fault
The pointer was made here:
char* ptr;
I passed it through the function as this:
fillDict(ptr,&size);
int fillDict(char* ptr,int *size)
And it reads the file and puts it into the array here:
int i = -1;
int numb;
int wsize;
while (fgets(word,30,file)!=NULL)
{
if (i==-1)
{
if(word[strlen(word)-1]=='\n')
{
word[strlen(word)-1] = 0;
}
numb = atoi(word);
ptr = malloc(sizeof(char));
}
else
{
if(word[strlen(word)-1]=='\n')
{
word[strlen(word)-1] = 0;
}
wsize = wsize+strlen(word);
ptr = realloc(ptr,wsize);
int j = 0; //added from here
while(j<strlen(word)-1)
{
printf("%d\n",j);
ptr[j] = word[j]; //crashes here
j++;
}
ptr[j] = '\0'; //to here
size++;
}
i++;
}
printf("%s",ptr[0]); //but fails here
fclose(file);
As #Jagannath mentioned, you are treating your ptr variable as a 2 dimensional array.
In reality, you allocate it as a simple buffer.
Schematically :
ptr = [][][][][][][][][][][][][][\0];
Then, you have a word which is also a simple buffer as follow :
word = [h][e][l][l][o][\0];
If you want to copy word to ptr, you need to iterate over both buffers and copy character by character as follow :
word = [h][e][l][l][o][\0];
v v v v v
ptr = [h][e][l][l][o][][][][][][][][][\0];
Otherwise, you can create an array of word by creating a 2 dimensional array.
ptr = [|][|][][]...[\0]
v v
[h][w]
[e][o]
[l][r]
[l][l]
[o][d]
[0][0]
Finally, you have flaws in your code. Look at your malloc(1)... And your wsize is never initialized, so when you do wsize = wsize+strlen(word); the behavior is undefined.
This code shows some fundamental misunderstanding about how pointers work. ptr[i] is equivalent to *(ptr+i). This makes no sense in the context of your code. It is therefore supposed to be a char but you are assigning a pointer to a char to it. And the printf that fails, well of course it's going to fail. it expects a pointer to a char but instead it gets whatever data is at the location ptr is pointing to and treats this as a pointer. This is likely to be a forbidden memory location hence the segfault. Even if it isn't, it is unlikely to reach a null terminating byte before it goes out of bound.
I noticed that many times when declaring variables/arrays/etc, people give it a null value or 0.
for example, take a look at the following snippet:
int nNum = 0;
char cBuffer[10] = { 0 };
int *nPointer = NULL;
and etc.
Untill asking this question I figured it would be for debugging purposes, since when I
was debugging a program with Visual Studio I noticed that variables that had no value had
undefined numbers as their value, whilst with 0 they had... 0.
There are a number of reasons to initialize variables to 0 or NULL.
First of all, remember that unless it's declared at file scope (outside of any function) or with the static keyword, a variable will contain an indeterminate value; it may be 0, it may be 0xDEADBEEF, it may be something else.
For sums, counters, and the like, you want to make sure you start from 0, otherwise you will get an invalid result:
int sum = 0;
while ( not_at_end_of_things_to_sum )
sum += next_thing_to_sum;
int count = 0;
while ( there_is_another_thing_to_count )
count++;
etc.
Granted, you don't have to initialize these kinds of variables as part of the declaration; you just want to make sure they're zeroed out before you use them, so you could write
int count;
...
count = 0;
while ( there_is_another_thing_to_count )
count++;
it's just that by doing it as part of the declaration, you don't have to worry about it later.
For arrays intended to hold strings, it's to make sure that there's a 0 terminator if you're building a string without using strcpy or strcat or scanf or similar:
char buf[N] = { 0 }; // first element is *explicitly* initialized to 0,
// remaining elements are *implicitly* initialized to 0
while ( not_at_end_of_input && i < N - 1 )
buf[i++] = next_char;
You don't have to do it this way, but otherwise you'd have to be sure to add the 0 terminator manually:
buf[i] = 0;
For pointers, it's to make it easy to test if a pointer is valid or not. A NULL pointer is a well-defined invalid pointer value that's easy to test against:
char *p = NULL;
...
if ( !p ) // or p == NULL )
{
// p has not yet been assigned or allocated
p = malloc( ... );
}
Otherwise, it's effectively impossible to tell if the pointer value is valid (points to an object or memory allocated with malloc) or not.
An uninitialized pointer variable may contain a garbage value. The purpose of initializing a pointer with NULL is that if you inadvertently use it without assigning a proper address, you do not end up modifying the contents at a random memory address.
Depending on the language, you would use NULL or just int *nPointer;
it's called initializing a variable, i.e. you're creating it. This is extremely helpful if you want your program to remain at a constant state, knowing that "un-initialized" variables won't cause an exception.
If you're inializing a varibale inside a loop or function, and you want to use it outside that loop/function and the loop/function only executes when there's a condition attached to it e.g:
if(nNum != 0){
int *nPointer = NULL;
for(int i=0; i<10; i++){
*nPointer++;
}
}
In this case if you did not initialize your variable, and you try and use it later down the line, your program might break. However, if it has been initialized, your safe, knowing it exists, but is still NULL.
SAFER CODE:
int *nPointer = NULL; //Or this will be a class member
if(nNum != 0){
for(int i=0; i<10; i++){
*nPointer++;
}
}