Is the same
char* s1[size];
To
char** s2 = malloc(size * sizeof(char*));
They have any difference?
Theoretically, *arr[] and **arr are different. For example :
char *arr[size]; //case 1
Here arr is a an array of size size whose elements are of the type char*
Whereas,
char **arr; //case2
Here arr is itself a pointer to the type char*
Note: In case 1 array arr degrades to a pointer to become the type char** but it's not possible the other way around i.e, pointer in case 2 cannot become an array.
char* s1[size];
Is an array of pointers of type char that is allocated on the stack.
char** s2 = malloc(size * sizeof(char*));
Is a pointer of type char ** that is allocated on the stack but points to a dynamic array of pointers of type char * allocated on the heap.
The two differ in terms of scope and the usual difference between arrays and pointers.
There are few differences:
s1 is not an lvalue, so it cannot be modified (e.g. using assignment or increment operators). Because of this it resembles type char** const s1 which also does not allow modifications (but in this case this is caused by const modifier).
operator & used on address of array will return address of array (i.e. address of 1st element). When & will be used on variable, it will return its address:
assert((void*)&s1 == (void*)s1);
assert((void*)&s2 != (void*)s2);
sizeof() used on array will return array size, while sizeof() used on pointer will return pointer size - usually it will be the same as sizeof(void*), but C standard does not require this (see comments below):
assert(sizeof(s1) == size * sizeof(char*));
assert(sizeof(s1) == size * sizeof(s1[0])); // this is the same
assert(sizeof(s2) == sizeof(void*)); // on some platforms this may fail
and of course obvious one - s1 is allocated on stack, s2 on heap. Because of this s1 will be destroyed automatically when execution leaves current scope, and s2 requires call to free to release memory.
Update: here is example code which checks above asserts:
#include <assert.h>
#include <stdlib.h>
int main()
{
const int size = 22;
char* s1[size];
char** s2 = (char**)malloc(size * sizeof(char*));
assert((void*)&s1 == (void*)s1);
assert((void*)&s2 != (void*)s2);
assert(sizeof(s1) == size * sizeof(char*));
assert(sizeof(s1) == size * sizeof(s1[0])); // this is the same
assert(sizeof(s2) == sizeof(void*)); // on some platforms this may fail
free(s2);
// Attempts to modify value
char** const s3 = s1;
++s2;
//++s1; // compilation error - lvalue required as increment operand
//++s3; // compilation error - increment of read-only variable ‘s3’
return 0;
}
s1 is an array, s2 is a pointer. s2 points to the first element of the malloced array.
The array s1 has automatic storage duration, while the array which s2 points to has dynamic storage duration.
Also, in C89 char* s1[size]; is valid only if size is a constant expression, because C89 doesn't support variable-length arrays.
Related
I am trying to allocate individual elements of two dimensional array in function call.
I am getting the pointer reference char ***a pointer in function parameter like this int substr(char *arr,char c,char ***a,int k)
But I am getting segFault at realloc line. I am not getting any help from -Wall -Wextra. In this example the function substr allocate for 1 index element of two passed two dimensional array
But I like to allocate memory in called function
#include <stdio.h>
#include <malloc.h>
#include <string.h>
int substr(char *arr, char c, char ***a, int k)
{
*(a + k) = realloc(a, 5);
return 0;
}
int main()
{
char *arr = "this is a new string. check it out";
char **a;
a[0] = malloc(5);
//....some code
//...
int count = substr(arr, ' ', &a, 1);
return 0;
}
From the conversation in the comments, there's some confusion about a[0]. Let's simplify it by working with char *.
// Declare the variable a which stores a pointer to a char.
char *a;
// Same as *a = 'b'
a[0] = 'b';
a[0] tries to access the memory a points to, same as *a. But a was never initialized, it points at some random memory you don't have access to, or is out of bounds. Segfault.
a has to have memory allocated to it to store 'b'.
// `a` points at 5 bytes of memory
// This is the same as `char *a; a = malloc(5)`.
char *a = malloc(5);
// The first byte of malloc'd memory is set to 'b'.
a[0] = 'b';
Now let's do it with an array of strings.
char **a;
a[0] = "some string";
Same problem. a is uninitialized and points at some random memory. a[0] = "some string"; tries to dereference a and segfaults.
So we need to first allocate space to store the pointers to the strings.
// Allocate space for 5 pointers.
// This is the same as `char **a; `a = malloc(...);`
char **a = malloc(sizeof(char *) * 5);
// Dereference the first pointer and have it point to a string.
a[0] = "some string";
Now to your code. Same thing.
char **a = malloc(sizeof(char *) * 5);
// Derefrence the first pointer in a and have it point to 5 bytes of memory.
a[0] = malloc(5);
If you want to reallocate the memory in a[0] you reallocate a[0], not a.
// Reallocate the 5 bytes of a[0] and return a pointer to 10 bytes.
// Assign the new pointer to a[0].
a[0] = realloc(a[0], 10);
If you want to do this in a function, pass in a pointer to the memory work with that. The function doesn't know nor care about the array a. Just the string.
// Note there's no need to pass in an array index.
void substr(char **dest) {
// dest is pointer to the pointer in a[0].
// *dest is the pointer in a[0], the malloc(5).
// Grow its memory and reassign it back to a[0].
*dest = realloc(*dest, 10);
// Assign to a[0] to demonstrate it works.
strcpy(*dest, "012345678");
}
int main(void) {
char **a = malloc(sizeof(char *) * 5);
a[0] = malloc(5);
substr(&a[0]);
puts(a[0]);
}
We can simplify this.
First, since a is allocated in main it can use automatic memory. This is memory which is automatically deallocated when the function exits. Because main is the first function it will be the last to exit, so any automatic memory in main will last for the whole program.
We can't use automatic memory in substr because it will be deallocated when substr returns.
Second, there's no need to allocate memory to a[0] if you're going to immediately realloc it. If you give realloc a null pointer it will allocate new memory.
int main(void) {
char *a[5];
a[0] = NULL;
substr(&a[0]);
puts(a[0]);
}
Finally, we can initialize all the pointers of a to NULL using a little syntactic trick.
int main(void) {
// Same as char *a[5] = {NULL, NULL, NULL, NULL, NULL};
char *a[5] = {NULL};
substr(&a[0]);
puts(a[0]);
}
Here is the code,
char const *words[] ={
"Hello",
"What are you doing",
0
};
int size = sizeof(words[1]), totalSize = sizeof(words);
The totalSize is is having the values 24 but size is having value 8. I used gdb to get a run-time look, for the command p words[1] result is $1 = 0x40400f "What are you doing" so words[1] is considered as array by debugger, still sizeof() is considering it as pointer. I don't understand why that is.
The fact that the debugger shows you the contents of the pointed string doesn't mean that the compiler refers to it as a statically allocated array (for which the sizeof operator can be applied "correctly").
You can retrieve those sizes (excluding null characters) using this piece of code:
int size = strlen(words[1]);
int totalSize = 0;
for (int i=0; words[i]!=0; i++)
totalSize += strlen(words[i]);
You may as well get rid of that last element in the words array, and use this instead:
int size = strlen(words[1]);
int totalSize = 0;
for (int i=0; sizeof(words)/sizeof(*words); i++)
totalSize += strlen(words[i]);
words is an array of 3 pointers to (const) char.
So sizeof with the array operand will yield the accumulated size of the 3 pointers and sizeof of an array element will yield the size of one pointer.
That's because the sizeof() operator is being replaced by the result at compile time. It should give the same result for all sizeof(words[i]) if used in a loop for example, so also for sizeof(words[1]). So the compiler interprets this simply as a (64-bit) pointer.
words is an array of char pointers. Therefore, its elements are of type pointers to char. words[1] is of type pointer to char not an array of char and that's why you are getting the size of pointer instead of the size of the string it points to.
How to find size of elements pointed by array of pointers?
In order to find the size of string that a pointer points to, you need to loop over it.
int size = 0;
char const *ptr = words[1];
while(ptr++)
size++;
or use standard library function strlen
size_t size = strlen(words[1]);
You declared array words like
char const *words[];
It means that each element of the array has type char const * and sizeof( words[0] ) is equivalent to sizeof( char const * ) that is equal in your environment to 8 bytes.
If you want to know the length of the string literal pointed to by pointer words[0] then you should use standard C function strlen declared in header <string.h>. For example
size_t length = strlen( words[0] );
Take into account that though all pointers in the array have the same size that is 8 bytes string literals pointed to by these pointers have different sizes.
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
int main(void)
{
char const *words[] =
{
"Hello",
"What are you doing",
0
};
const char **p = words;
for ( ; *p; ++p ) printf( "\"%s\": %zu\n", *p, strlen( *p ) );
return 0;
}
The output is
"Hello": 5
"What are you doing": 18
The string literals themselves have types in C correspondingly
char [6] and char[19] because they include the terminating zero.
The initial box shows the base address of the string.
+----+ +-----+
|1000|--->|Hello|
+----+ +-----+
words[0]
+----+ +------------------+
|2000|--->|What are you doing|
+----+ +------------------+
words[1]
if you perform sizeof(words[0]), which is a pointer of type char const* and we all know that the size of the pointer remains the same for all data type usually 4, but in you case its 64 bit machine and hence you are getting 8 as a output.
Even the sizeof(words[1]) would fetch you 8 for the same reason.
Use a pointer to a pointer concept for fetching the words at that base address.
Consider char *a[] = {"abc", "xyz", "def"};
Deep copy char *a[] to char **b.
Can someone say what is deep copy? And how much memory we need assign to b?
char *a[n];
Is an array of n pointers-to-char. Each element of the array is contiguous in memory. The size in memory required is
sizeof(char *) * n
I've used the sizeof() operator here... you could assume 4 bytes for a pointer but this might not be safe... this depends on your hardware.
char **b
Is slightly different. This is a pointer to a point-to-char. **b has not allocated the array of pointers. First allocate the array...
char **b = malloc( sizeof(char *) * n);
EDIT: Thank you to interjay for pointing out my mistake... example below now uses strdup() to allocate the memory for each b[i]
**b points to the start of an array of n pointers. For each pointer in that array you could so do b[0] = a[0] for shallow copies
This is a shallow copy because b[0] will point to the same memory that a[0] points to. Thus changing the contents b[0] will change the contents of a[0].
A deep copy would imply that you have two totally independent entities... so changing the contents b[0] would not result in a change to the contents of a[0]. This means that for each b[i] you need to allocate new memory and copy the string from a[i] into that new block.
To deep copy:
char *a[n];
// ...intialise array a....
char **b = malloc( sizeof(char *) * n); // allocate array of pointers
if( b )
{
int i = 0;
for(; i < n; ++i)
b[i] = (char *)strdup(a[i]); // allocate memory for new string and copy string
}
else
printf("You ran out of memory!\n");
As an asside...
You've used constant strings so you shouldn't technically modify them...
char *xxx = "String";
char yyy[] = "String";
You can safely modify the contents of yyy. Normally you can modify the contents of xxx without any problem, but note, because the string memory is allocated at compile time, you could find that the compiler has, for example, placed it in read only memory.
EDIT:
There seems to have been debate on whether to cast return from malloc (which I've been in the habit of doing, but it seems this was a bad habit!)... see Why do we need to cast what malloc returns?
Walking on the a array, for eah a[i] request space to alloc it by using one of *alloc() family functions and put the result in the respective b[i]. The b pointers itself shall be a pointer with enough space for hold the number of string in a as pointers. Compute with something like this:
int bsize = (sizeof(a)/sizeof(a[0])) * sizeof(char*);
char **b = malloc(bsize);
int i,len;
/* if(b == NULL) /* error: no memory */
for(i = 0,len = sizeof(a)/sizeof(a[0]); i < len; i++) {
char *tmp = malloc(strlen(a[i])+1);
if(tmp == NULL) /* error: no memory */
strcpy(tmp, a[i]);
b[i] = tmp;
}
Note that you need to or hold the size of b array in memory either put a NULL at end of array.
You can just do
b=a
This will assign base address of array of pointers *a[3] to b.
Now you can access strings using b
for example string 1 can be accessed by *(b+0) gives address of string 1
string 2 " " *(b+1) " " string 2
string 3 " " *(b+2) " " string 3
Since you are assigning array of pointers to pointer to a pointer you are already assigning memory to b Hence you do not need to use malloc.
Only when you are assigning some data to a pointer at run time and you have not assigned memory to pointer in your program then only use malloc.
char** args = (char**)malloc(MAX_ARGS*sizeof(char*));
and
char* args = (char*)malloc(MAX_ARGS*sizeof(char*));
Please explain the difference between these two types of declaration. Why do we need 2 stars and why 1 star?
In both cases, the cast is unnecessary and can mask errors; I'll delete the casts in the following. (malloc() returns a void*, which can be implicitly converted to a pointer-to-whatever.)
char **args = malloc(MAX_ARGS*sizeof(char*));
This defined args as a pointer-to-pointer-to-char, and initializes it to point to a chunk of memory big enough to hold MAX_ARGS elements, each of which is a char*. Once you've done this, you'll want to assign values to those char* elements, likely making them point to strings.
char *args = malloc(MAX_ARGS*sizeof(char*));
This is legal, but almost certainly a logical error. args is a pointer-to-char, which means it can point either to a single char object, or to the first element of an array of char elements. But you're allocating memory that can hold MAX_ARGS pointers.
A more likely thing to do is:
char *s = malloc(MAX_LEN);
which will cause s to point to a region of memory that can hold MAX_LEN char elements (a string of length up to MAX_LEN - 1). (Note that sizeof (char) == 1 by definition.)
There's a useful trick to avoid type mismatches. A pointer of type FOO*, for any type FOO, needs to point to a chunk of memory big enough to old one or more elements of type FOO. If you write:
ptr = malloc(count * sizeof *ptr);
and ptr is a FOO*, then sizeof *ptr is the same as sizeof (FOO) -- but you won't have to update the line if you later change ptr to be a pointer toBAR`.
In your case, the pointed-to type is itself a pointer, so you can write:
char **args = malloc(MAX_ARGS * sizeof *args);
And when you call malloc, you should always check whether it succeeded, and take some action if it failed -- even if that action is to terminate the program with an error message:
if (args == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
2 stars are like matrix (or a two dimensional array). First malloc only gets memory for the first line (you have to iterave over its elements making the second malloc to reserve space for the other ones).
The two stars mean a pointer-to-a-pointer_type-to-data_type. So in the case of a char** this is saying create an array of char*[MAX_ARGS].
So for this case the following would be valid as args[n] is a char*:
args[0] = (char*)strdup("aaa");
args[1] = (char*)strdup("bbbb");
args[2] = (char*)strdup("ccccc");
NOTE: you should remember to free each member of the array prior to freeing args otherwise the pointers are lost.
With a single star it is just a pointer-to-data and essentially you are writing char[MAX_ARGS*sizeof(char*)]
For this args[n] is a char type:
args[0] = 'a';
args[1] = 'b';
args[2] = 'c';
With this char-array you are creating a simple array of characters, also known as a c-style string.
Here is my code:
printf("%s\n", "test1");
char c = '2';
char * lines[2];
char * tmp1 = lines[0];
*tmp1 = c;
printf("%s\n", "test2");
I don't see the second printf in console.
Question: Can anybody explain me what's wrong with my code?
NOTE: I'm trying to learn C :)
This line:
char * lines[2];
declares an array of two char pointers. However, you don't actually initialize the pointers to anything. So later when you do *tmp1 = (char)c; then you assign the character c to somewhere in memory, possibly even address zero (i.e. NULL) which is a bad thing.
The solution is to either create the array as an array of arrays, like
char lines[2][30];
This declares lines to have two arrays of 30 characters each, and since strings needs a special terminator character you can have string of up to 29 characters in them.
The second solution is to dynamically allocate memory for the strings:
char *lines[2];
lines[0] = malloc(30);
lines[1] = malloc(30);
Essentially this does the same as the above array-of-arrays declaration, but allocates the memory on the heap.
Of course, maybe you just wanted a single string of a single character (plus the terminator), then you were almost right, just remove the asterisk:
char line[2]; /* Array of two characters, or a string of length one */
The array lines in uninitialized. Thus lines[0] is an uninitalized pointer. Dereferencing it in *tmp1 is sheer undefined behaviour.
Here's an alternative, that may or may not correspond to what you want:
char lines[2];
char * tmp1 = lines; // or "&lines[0]"
*tmp = c;
Or, more easily:
char lines[2] = { c, 0 };
lines is uninitialized, and tmp1 initialization is wrong.
It should be:
char lines[2];
char * tmp1 = lines;
Alternatively, you can say:
char * tmp1 = &lines[0];
Or else for an array of strings:
char lines[2][30];
char * tmp1 = lines[0];
The line
char * lines[2];
creates an array of two char pointers. But that doesn't allocate memory, it's just a "handle" or "name" for the pointer in memory. The pointer doesn't point to something useful.
You will either have to allocate memory using malloc():
char * lines = malloc(2);
or tell the compiler to allocate memory for you:
char lines[2];
Note: Don't forget to terminate the string with a 0 byte before you use it.
char *lines[2]; : A two element array of char pointers.
char *tmp; : A pointer to a character.
char *tmp = lines[0] : The value inside the array element 0 of the lines array is transferred into tmp. Because it is an automatic array, therefore it will have garbage as the value for lines[0].
*temp : Dereference the garbage value. Undefined Behaviour.
char * tmp1 = lines[0];
here you declare a char pointer and initialize its pointer value to line[0],the fist element stored in line array which is also uninitialized.
now the tmp is pointing to somewhere unknown and not actually accessible. When you
*tmp1 = (char)c;
you are operating on a invalid memory address which causes a Segmentation fault.