This is what my main functions looks like. This cannot be changed as it is being used in the file my professor is using to grade the assignment.
char** lines = NULL;
int line_count = 5;
add_lines(&lines, line_count);
In this function, I need to dynamically allocate the lines array and store multiple strings inside. The memory is then being freed in main. This is how I am currently doing it, but I keep getting a segfault. (This function also must take a char***).
void add_lines(char*** lines, int line_count) {
*lines = (char**)malloc(line_count*sizeof(char*));
for (int i = 0; i < line_count; i++)
*lines[i] = (char*)malloc(64*sizeof(char));
}
I am assuming this error has to do with dereferencing and trying to dynamically allocate a NULL pointer, but I'm not sure how I'd go about fixing it.
This line isn't doing what you think:
*lines[i] = (char*)malloc(64*sizeof(char));
The array index operator [] has higher precedence than the unary dereference operator *. So it attempts to access lines as an array (which it isn't), then dereference the array member. This ends up working when i is 0 because it will point to the first allocated array element, but when i is larger you access memory past lines in the calling function.
You need to use parenthesis to make sure you dereference lines first, then index the array elements.
(*lines)[i] = malloc(64*sizeof(char));
Also, don't cast the return value of malloc. It's unnecessary and can mask subtle bugs.
Related
I’m taking a C class on Udemy. Unfortunately the instructor isn’t replying to my question so I thought I’d try this site. My assumption is that it is probably fairly common when developing a program to not know how many elements may be part of an array. When initializing an array the instructor recommends not specifying a size but to let the compiler do it.
Example: int array[ ] = {2,3,4,5,6,7,8};
Obviously, using this method there is no index to use to terminate looping. According to “C Primer Plus” by Stephen Prata the element after the last element in the array is a valid pointer location:
(pg. 406) - C guarantees that when it allocates space for an array, a
pointer to the first location after the end of the array is a valid
pointer.
If I’m using pointer notation (array++) to loop through the array, what condition can I use to terminate the looping? Is there a value in that location after the final element that I can use? Is that value always the same or does it change depending on the type of array?
In C pointers are signed. That has consequences dealing with array-like data structures where you might:
while (a <= a+last) {
...
a++;
}
if the index one beyond the end of a could have a change of sign, then that code could fail. Idiomatic C does not suggest the above; but it needs to be preserved, thus this limitation.
In system code, it is possible that you deal with allocations that do not conform to this, thus you should try to work with the idiomatic:
while (a < a+len) {
...
a++
}
So, for your exact question:
for (size_t i = 0; i < sizeof array/sizeof array[0]; i++) {
...
}
or
for (int *p = array; p < array + sizeof array / sizeof array[0]; p++) {
...
}
Your basic idea (looping through an array using pointers) is sound; however, there are a number of points in your question that need some attention.
Is there a value in that location after the final element that I can use? Is that value always the same or does it change depending on the type of array?
Yes, there is a (almost certainly) some value in that location, but it's not something you can ever use! The pointer to the 'one-past-the-end' element is valid only for use in pointer arithmetic or comparison operations; attempting to dereference it (to read the value at that address) is undefined behaviour.
You can get that 'one-past-the-end' pointer by adding the number of elements in the array to the address of the array's first element (or the array 'name' itself). The idiomatic way to get the number of elements in an array is to divide the size of the entire array by the size of its first element. So, for your array, we can declare and initialize our "end pointer" like this, using the sizeof operator:
int* end = array + sizeof(array) / sizeof(*array);
// int* end = array + sizeof array / sizeof *array; // Alternative form: "()" optional
Another important point: In your question you mention using array++ to loop through your array variable. You cannot do this, because array isn't actually a (modifiable) pointer variable – it's the name of a variable (an array) whose location is fixed at the point when main (or whatever function it is declared inside) is entered. Instead, you will need to copy the address of the array into another int* pointer, and increment that in the loop.
With those points in mind, here's an illustrative example of how you can loop through your array using a pointer:
#include <stdio.h>
int main(void)
{
int array[] = { 2,3,4,5,6,7,8 };
int* end = array + sizeof(array) / sizeof(*array);
for (int* p = array; p < end; ++p) {
// Note that, when we reach p == end, the loop will not run, so ...
printf("%d\n", *p); // ...we never attempt the *p operation on that
}
return 0;
}
A couple of other points of clarification:
The int* p = array assignment works (and is perfectly valid C) because an array variable name can readily decay into a pointer to its first element (as it will if you pass that array as an argument to a function, for example). See: What is array to pointer decay?
Because of that last point above, you cannot use the sizeof(a)/sizeof(*a) paradigm to determine the size of an array in a function it is passed to as an argument; in such cases, you need to pass the array's size as an additional argument. See: How do I determine the size of my array in C?
//1
char** p;
p[0]="Test";
//2
char** array;
array = realloc(array, sizeof(char*)*((*size)+1));
array[*size] = (char*)malloc(sizeof(char)*(strlen(input)+1));
Why does the first code fails in the second line, while the the second code works fine, doesn't array[*size] is just like p[0]?
Examining the code:
char **p; // Declared, but uninitialized
p[0] = "test"; // Setting value to it?
p is uninitialized, and as such, trying to access and set memory with it is UB, or undefined behavior. Failing is much better than potential alternatives.
For the second piece of code, assuming size is some pointer not included in the snippet.
char** array
array = realloc(array, sizeof(char*)*((*size)+1)); // Allocating.
array[*size] = (char*)malloc(sizeof(char)*(strlen(input)+1));
So, strictly speaking, calling realloc with an uninitialized pointer is UB, by chance array is equal to Null.
Note that:
If ptr is NULL, the behavior is the same as calling malloc(new_size).
As such, realloc will allocate a chunk of memory and pass it to array.
You then dereference the pointer (which is no longer pointing to Null but a valid spot in memory), and malloc it, which does not crash.
From the best guess, while this is undefined behavior, p is possibly Null in both cases, and the first one crashes when trying to dereference it, and the second one successfully gets malloced.
I got this tiny little program down here, that comes with preassigned 'count' number and then parses it to format of 'xxx', where x is a 0 or corresponding cipher (e.g from '6' I got 006 and from 234 I get 234). When I get it like this
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
int count = 0;
char number[2] = {0};
int base0 = count % 10;
int base1 = ((count % 100) - base0) / 10;
int base2 = ((count % 1000) - base1) / 100;
sprintf(number, "%d%d%d", base2, base1, base0); //print into the number variable
printf("%s\n", number);
}
everything is working fine, but if I switch 'number' variable definition with
char* number = NULL;
I get segmentation fault. Why is that? It should just point to the beggining of the string.
In C, a string is represented as an array of characters; the line
char number[2] = { 0 };
therefore defines a two character array ('string') initialised with two null characters.
An array is a series of contiguous (read 'next to each other') blocks of memory that can each be individually accessed via the subscript operator (square brackets).
When you changed the above line to
char* number = NULL;
You are no longer defining a character array. In this case you are now defining a pointer to char variable. Because arrays are basically blocks of memory next to each other, if you know where the first element is, it is possible to then locate any of the others. So since the deference operator allows you to access the value pointed at by a pointer, you can access the ith element in a string with
*(char + i)
which in C is exactly equivalent to
char[i]
Now in your case, you haven't set the char* to point to actual memory containing a real string, you have assigned the NULL pointer, which means 'this pointer points nowhere'. Treating a char* as a string requires it to be dereferenced (following the pointer); however, dereferencing a NULL pointer is an undefined behaviour, which in this situation has caused a seg fault
NULL is a well-defined "nowhere" - it's an invalid pointer value that's guaranteed not to point to a function or an object in memory. When you set number to NULL, you're saying that number isn't pointing anywhere meaningful.
Trying to work through an invalid pointer leads to undefined behavior - in this case, a segfault.
Arrays and pointers are not the same thing. Array expressions will "decay" (be converted) to pointer types in most circumstances, but the object is always an array.
"everything is working fine,"
Wait there. You already have sever shortage of required memory. In case of
sprintf(number, "%d%d%d", base2, base1, base0);
number needs much more memory to stay within the bounds, so as is, your program invokes undefined behavior by accessing out of bound memory. You need to allocate enough memory to hold the final sting to be held by number.
Anyways, NULL is defined to be an invalid memory location, accessing which invoke UB again, so you cannot use it to store anything, at all.
char number[2]; gives you two bytes of memory for number
char * number = null; gives you zero bytes of memory for *number.
When you do sprintf, you are writing three bytes into the number.
When say "char *number = null", you are writing into null, which results in segfault.
When you do sprintf, you are writing 3 bytes into 2 bytes of allocated memory - you are overwriting 1 extra byte into stack.
I'm a Java programmer struggling to understand C pointers and arrays. (FULL DISCLOSURE: I'm also a CS student, and yes, this question helps me with a programming assignment.)
I'm trying to create an array of int* pointers, then ensure that every pointer is NULL. Later, this will come into play when I need to look up data in the array; whether there is a valid int or a NULL in a given spot will be important.
So allocating the space for the array is easy, but how to set all those pointers to NULL? Here's my less-than-stellar attempt:
#include<stdio.h>
#include<stdlib.h>
#define TABLESIZE 10
int main(int argc, char *argv[]){
int* table = (int*) malloc(TABLESIZE * sizeof(int));
// Initialize all *int pointers to NULL
int i;
for(i=0; i<TABLESIZE; i++){
if((table+i)!=NULL){ // They may be NULL already? I don't know...
*(table+i) = NULL; // This generates a warning:
// "warning: assignment makes integer from pointer without a cast [-Wint-conversion]"
}
}
// Sanity check : are all int* are NULL ?
for(i=0; i<TABLESIZE; i++){
printf("%d: %p %d ", i, (table+i), *(table+i));
if((table+i) == NULL)
printf("(NULL)");
printf("\n");
}
free(table);
return 1;
}
Output is:
$ ./a.exe
0: 0x6000103c0 0
1: 0x6000103c4 0
2: 0x6000103c8 0
3: 0x6000103cc 0
4: 0x6000103d0 0
5: 0x6000103d4 0
6: 0x6000103d8 0
7: 0x6000103dc 0
8: 0x6000103e0 0
9: 0x6000103e4 0
$
So I'll be flat-out honest... I don't know what the above tells me. I'm guessing that I've created a 1D array where all the values in the array are valid ints, all 0.
But this is problematic for later in my program. When it comes time for my code to insert data into table[x], the code must be able to look at the array and know if another valid int was previously inserted in the same spot. If it sees table[x] = 0, does it conclude a 0 was inserted into index x, or that the spot is available?
I liked the idea of using an array of pointers to ints because that would neatly solve this problem. If my code saw:
table[x] --> NULL // This spot is empty and available
table[x] --> 0 // This spot is occupied, can't insert here
But I don't think I'm coding what I want.
Any thought/advice/comments/criticism is greatly appreciated.
Thanks!
-Pete
int* table = malloc(TABLESIZE * sizeof(int));
Does not create an array of pointers, rather it creates a single int pointer to the start of block of allocated memory of size (TABLESIZE * sizeof(int))
The reason you are getting an error is that an int* is just that; a pointer to an int.
The * operator is called the 'dereference' operator. Its job when placed before a variable is to say 'go to wherever this pointer is pointing'. Therefore, the line
*(table+i) = NULL;
Means 'go to wherever table is pointing, move along i * sizeof(int), then set that particular int to NULL. This obviously doesn't make sense - you can't set a an int to NULL, as that's a pointer value. Hence your error.
By the way, since pointers can also be treated like arrays in C, the above line is also the exact equivalent of
table[i] = NULL;
If you want your initial malloc to be an array of pointers you need to allocate space not for int but for int*, so you could do
int** table = malloc(TABLESIZE * sizeof(int*));
Then you have an int** (Double pointer - aka a pointer to a pointer) referencing a block of TABLESIZE int*'s
Once you have done this, the code below that line will correctly set your pointers to NULL. To then achieve the table as described in your question, you will need to do a further malloc for each cell before you put an int in it. So for example to put '3' into cell 2
if(*(table + 2) == NULL) {
*(table + 2) = malloc(sizeof(int));
}
**(table + 2) = 3;
Note the double deference on the last line: 'Go to wherever table is pointing, move along 2 * sizeof(int*), then go to wherever that pointer is pointing.' Again, this can also be achieved with array syntax
if(table[2] == NULL) {
table[2] = malloc(sizeof(int));
}
*table[2] = 3;
Be careful not to call malloc() on the same cell twice; if you do this you will have a memory leak.
I'm a Java programmer struggling to understand C pointers and arrays.
Yes, the "struggling" part is evident in your code.
A C array is simply an ordered collection of elements of a specified type, arranged contiguously in memory. This is similar to a Java array, but Java provides no means for you to see or probe the arrangement of the elements in memory, and its arrays have additional data associated with them (in particular, they know their own lengths).
A C pointer is a value that represents the address of some other object, where "object" means a stored value of any type, including built-in (Java: "primitive") types, aggregate types (structures and arrays), pointer types, and even no particular type. This is similar in some ways to a Java "reference", which is reflected in the fact that Java raises "NullPointerException" if it tries to dereference a null reference.
It is very important to understand that although there is a close relationship between arrays and pointers, they are not at all the same thing. That should be clear from the descriptions above, but I regularly come across clueless claims to the contrary.
It is also important to understand that pointer values can be invalid -- not pointing to any object. You can easily have a pointer value, maybe stored in a variable or an array, whose value is garbage. This is something to manage, not to be afraid of.
Furthermore, it is important to understand that pointer values do not necessarily have to be obtained via memory allocation functions. They can also be obtained via the address-of operator (&) or through evaluation of an expression involving an array, or garbage pointer values can spring up naturally when a pointer is declared but not initialized.
I'm trying to create an array of int* pointers
I'm not sure whether you mean an array whose elements have type int * (pointer to int), an array whose elements have type int ** (pointer to pointer to int), or maybe an array whose elements have type int. My guess from your wording would be the first, reading you literally yields the second, and your actual code presents something like the third.
This would be the declaration of an array of int *:
int *table[TABLESIZE];
Not having specified an initializer, you cannot rely on any particular values for the elements until you assign values. Code similar to what you presented could be used for that (less the NULL check, which has undefined behavior on account of the initial values being indeterminate, and anyway would provide no advantage whatever), but I'd be inclined to write it slightly differently:
for (int i = 0; i < TABLESIZE; i++) {
table[i] = NULL;
}
At this point, the elements of your table are all initialized with the one pointer value that you can be certain does not point to any object. You can check those pointer values, but you must not dereference them:
// Sanity check : are all int* are NULL ?
for(int i = 0; i < TABLESIZE; i++) {
printf("%d: %p ", i, (void *) table[i]);
if(table[i] == NULL)
printf("(NULL)");
printf("\n");
}
I liked the idea of using an array of pointers to ints because that
would neatly solve this problem. If my code saw:
table[x] --> NULL // This spot is empty and available
table[x] --> 0 // This spot is occupied, can't insert here
That does not make sense, because 0 interpreted as a value of any pointer type is a null pointer constant. However, having started by assigning all elements of the table to be NULL, if you intend to set elements to valid pointers when you assign them, then you can check for NULL to see whether a spot is available, since NULL is never a pointer to an object.
Do note, by the way, that if you declare table as a bona fide array, as above, then you do not need to free it. You might, however, need to free some or all of the objects to which its elements point, depending on whether those objects were dynamically allocated, and on whether they have been or will be freed by other means.
In both C and Java, int holds an integer value. There is no additional, distinguishable null state. Usually, every possible bit-pattern for an int represents a distinct integer value, so it is not physically possible to store this extra state.
If you want to implement something that can be "either 'null' or any possible value in the range of int" then you will have to use additional storage for each array entry. (For example, you could maintain a parallel set of boolean flags indicating whether each entry is "active" or not).
An alternative solution would be to reserve one particular integer value to represent that that array entry should be considered "empty". This technique is called sentinel value.
In Java you can have an array of Integer , which is an array of references that may either be "null" or refer to an int stored elsewhere (the language manages the allocation behind the scenes). To simulate that memory layout in C
the code would be:
// Allocate array and initialize all entries to NULL
int * array[ARRAYSIZE] = { NULL };
// Insert at position (repeatable)
if ( array[2] == NULL )
array[2] = malloc( sizeof(int) );
*array[2] = 10;
// Use item
printf("%d\n", *array[2]);
// Remove from position
free( array[2] );
array[2] = NULL;
To avoid memory leaks you will need to remember to loop through and do the removal procedure before array goes out of scope. It would also be good to check for malloc failure and abort the program or take some other action.
Note that this technique would be considered unusual in C, and not space-efficient compared to the other available options.
I have code that functions like this:
void** array;
array = malloc(8*sizeof(void*));
And if I put, say, three elements into the array and try:
int i = 0;
for(i; i < 8; i++)
free(array[i]);
It fails after 6 iterations of the loop. But if I populate the entire array (with 8 elements), the for loop executes just fine. I've tried this with 18 as well, and the loop fails after 9 iterations, but if I populate the whole thing it executes fine.
Can someone please explain what's happening here?
The memory returned by malloc is not initialized; it may contain garbage data. You're allocating an array of pointers, but its initial contents are not valid pointers. You're setting some of the items to (presumably) valid pointers, but leaving others uninitialized, and then you call free on all the items — even the uninitialized garbage ones.
You need to either:
keep track of which items in the array have been set to a valid pointer, and call free only on those items, or
explicitly initialize all the items to NULL. This makes it safe to free them all, since free(NULL) is valid (and does nothing).
Memory allocated for and assigned to pointer to pointer is of type pointer so as to assign further memory for the inner pointers to hold the actual data i.e int** is assigned with memory of int* so that ints can be assigned to the allocated int*:
// array is a double pointer variable
void **array = malloc(8 * sizeof *array); // (1) allocate memory for 8 void* pointers
for (int i = 0; i < 8; ++i)
array[i] = malloc(sizeof(int));
// (2) - malloc for the actual data to be pointed by the above allocated pointers
then you've to do this for freeing the memory
for (int i = 0; i < 8; ++i)
free(array[i]); // undo (2)
free(array); // undo (1)
You've to match every malloc with a free. Since you've done only 1, you should undo only 1.