I've created a 2D array using this:
struct Cars (*ParkingLot)[FloorCount] = malloc(sizeof(struct Cars[FloorCount][10]));
I don't know if it matters but the FloorCount is set to 1 for now, and struct Cars is defined this way:
struct Cars
{
int ID;
char color[20];
char type[20];
};
Anyway, I'm trying to use this array in a function, and I can't access the values inside the array.
For example, the next thing:
void CarIn (struct Cars *Lot[])
{
printf("%d", Lot[0][0].ID);
}
ParkingLot[0][0].ID=15;
CarIn(ParkingLot);
That's not what I wanna do, but it's the most basic function I can think of using the array, it will help me with the rest.
Edit:
Well, I've managed to print using the function, all I needed is to add & before the Lot[0][0].ID...
The other problem I have now is that this function doesn't seem to work at all, it always crash:
void CarIn (struct Cars *Lot[],struct Cars New)
{
Lot[0][0]=New;
return;
}
First, your sizing is wrong in your allocation declaration for ParkingLot. I assume you want 10 cars per floor and an arbitrary number of floors, and if that is the case, then this should be done as:
struct Cars (*ParkingLot)[10] = malloc(FloorCount * sizeof *ParkingLot);
ParkingLot is a pointer to an array of 10 Cars (not 10 pointers to Cars; rather 10 Cars in sequence). sizeof *ParkingLot will calculate the memory requirement for holding that many sequential Cars structures, and finally, multiplying by FloorCount will give you that many floors, of that many cars. For sanity sake you could (and probably should) use the array allocator in the standard library, calloc, though it isn't strictly needed. It would look something like this:
struct Cars (*ParkingLot)[10] = calloc(FloorCount, sizeof *ParkingLot);
Some find it clearer, and relish in the fact it zero-initializes the allocated memory.
On to your question, to pass a true array of arrays (as opposed to an array of pointers) your function parameter declaration is incorrect.
This:
void CarIn (struct Cars *Lot[])
declares an arbitrary-length array of struct Cars *, and indeed the above is equivalent to this:
void CarIn (struct Cars **Lot)
You want neither of those if your intent is to pass a true array of arrays (which is what your allocation is indeed acquiring). Instead, you want something like this:
void CarIn (struct Cars Lot[][10])
or equivalently, this:
void CarIn (struct Cars (*Lot)[10])
To pass a true array of arrays to a function, all dimensions but the most-superior must be provided in the declaration. The above declare an arbitrary length array of element-count-10 arrays of Cars.
Note: This can be done with variable-length syntax as well, if the sizing for the array of arrays inferior dimension is runtime-generated, but that doesn't seem to be your question (yet). For now, the above should get you where you want to go.
Best of luck.
struct does not create a 2D array, struct creates a structure - a 'template' that unifies different data types and stores them as an 'unity' in memory
A 2D array is created by i.e. int 2Darray[3][4] = {{0,1,2},{8,9,10,11}};
A 2D array of a structure is created by i.e. struct Cars cars2Darray[10][10];
See this http://www.tutorialspoint.com/cprogramming/c_multi_dimensional_arrays.htm
To pass a 2D array to a function as argument one possible method is to use a pointer to the 0-element of the array i.e. 2D_array[0] (if the array is named 2D_array).
In the following the pointer 'ptr' points to the 0-element of the int-array '1D_array'
int 1D_array[8]= { 1, 2, 4, 8, 16, 32, 64, 128 };
int *ptr;
ptr = 1D_array;
The ptr = 1D_array stores the address of the 0th element of 1D_array in ptr, so ptr now points to the 0-th element of 1D_array
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int 1D_array[8]= { 1, 2, 4, 8, 16, 32, 64, 128 };
int *ptr;
int i;
ptr = 1D_array;
printf("The value, *ptr points to, is %d\n", *ptr);
printf("When applying *ptr+1 it points to %d\n", *(ptr+1));
printf("*(ptr+3) = %d\n", *(ptr+3));
printf("\n all elements of 1D_array : \n");
for(i=0; i<8; i++)
printf("element[%d]=%d \n", i, *(ptr+i));
return EXIT_SUCCESS;
}
As ptr now points to the 0th element of 1D_array you can use it to pass the array to a function.
For how to pass a 2D array to a function there are 3 methods (2 using pointers) see this Correct way of passing 2 dimensional array into a function
Related
I am loading some data into struct.
struct test {
char x[101];
char y[101];
int z;
};
Then I create memory for structs
struct test * data;
data = malloc(10 * sizeof(struct test));
And fill data like this
data[0].z = 123;
This works alright. But I wanna sort these structs. Like sort them depending on z attribute.
My idea was to create a new array and fill it with pointers which will point to the right struct.
Can somebody tell me how or if there is better way?
Thanks
This depends on your goal. If you are trying to figure out what would be most programmer efficient, then creating an ordering functor based on the z attribute of your struct, and sorting the list directly, is easiest.
However, if you are concerned with program efficiency, then it will be faster to sort pointers, as suggested by Fiddling Bits. However, you must keep in mind that this will give you a sorted list of pointers- your data array will still be in the same order.
For instance, if datapoints is your array of pointers, and you wanted to sort by the z value, you could define the comparison
int compare(const void *a, const void *b)
{
return ( (*(test *)a).z -(*(test *)b).z );
}
And then call
qsort( datapoints, 10, sizeof(test), compare);
Full documentation for qsort can be found here:
One way to do this is using qsort, the general sorting algorithm provided in the standard library for sorting sequences of user-defined data. With a goal of doing the following:
the source data must remain un-touched.
the "sorted" access must be provided via a list of pointers to the untouched data from above
this is one way to do that using the qsort() standard library function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
struct test {
char x[101];
char y[101];
int z;
};
int cmp_test_ptrs(const void* arg1, const void* arg2)
{
struct test const * lhs = *(struct test const * const*)arg1;
struct test const * rhs = *(struct test const * const*)arg2;
return (lhs->z < rhs->z) ? -1 : (rhs->z < lhs->z);
}
int main()
{
srand((unsigned int)time(0));
// populate data array.
struct test * data = malloc(10 * sizeof(*data));
for (int i=0; i<10; ++i)
{
data[i].z = rand() % 20;
printf("%d ", data[i].z);
}
printf("\n");
// allocate a pointer array to use as a sort-bed, copying each
// structure address into this pointer array afterward
struct test **ptrs = malloc(10 * sizeof(*ptrs));
for (int i=0; i<10; ++i)
ptrs[i] = data+i;
// sort the pointer bed using our comparator
qsort(ptrs, 10, sizeof(*ptrs), cmp_test_ptrs);
// ptrs now has sorted pointers. Note the dereference for access
// to the actual data, which remains where it originally was.
for (int i=0; i<10; ++i)
printf("%d ", ptrs[i]->z);
printf("\n");
free(ptrs);
free(data);
return 0;
}
Sample Output
11 7 6 17 8 8 11 4 7 5
4 5 6 7 7 8 8 11 11 17
Important to note is the original structure array remained untouched. We sorted a sequence of pointers, not the actual structures themselves, and used what those pointers pointed-to as the criteria for the sort.
Anyway, I hope it helps. Study the comparator and the setup for qsort() carefully. They're important. You can read more about qsort() here.
Or you can just sort them in the same array and probably save some memory (4 bytes for a pointer of any type) :P
Doesn't really matter though, pointers'll work fine I guess.
But I think that in some cases pointers will be more useful as if you would sort it in the array you'll need a temporary struct defined to contain structs when you're sorting and if you're struct is big than you'll actually take a lot more memory than 4 bytes.
+Also remember that when defining a pointer to a struct - access it with -> operator.
Usage: STRUCT_POINTER_NAME->VARIABLE
I need to write a function that sums monoms with the same power,
the monoms are defined by the following struct:
typedef struct monom {
int coefficient;
int power;
}MONOM;
And the function I wrote from the job is:
int sumMonomsWithSamePower(MONOM** polynomial, int size)
{
int i, powerIndex = 0;
for (i = 0; i < size; i++)
{
if ((polynomial[powerIndex])->power == (polynomial[i])->power)
{
if (powerIndex != i)
(polynomial[powerIndex])->coefficient += (polynomial[i])->coefficient;
}
else
powerIndex++;
}
powerIndex++;
*polynomial = (MONOM*)realloc(polynomial, powerIndex);
return powerIndex;
}
Which is being called with the following call:
*polySize = sumMonomsWithSamePower(&polynomial, logSize);
polynomial array is being sent to the function as a sorted array of MONOMs (sorted ascending by powers).
My problem is that on the 7th line of sumMonomsWithSamePower() the function crashes since it can't see the elements in the array by the following way. When I put the elements of the array in Watch list in my debugger I also can't see them using polynomial[i], but if I use (polynomial[0]+i) I can see them clearly.
What is going on here?
I assume outside sumMonomsWithSamePower() you have allocated polynomial with something like polynomial = malloc( size * sizeof(MONOM) ); (everything else wouldn't be consistant to your realloc()). So you have an array of MONOMs and the memory location of polynomial[1] is polynomial[0] + sizeof(MONOM) bytes.
But now look at polynomial in sumMonomsWithSamePower() In the following paragraph I will rename it with ppoly (pointer to polynomial) to avoid confusing it with the original array: here it is a MONOM **, so ppoly[1] addresses the sizeof(MONOM *) bytes at the memory location ppoly[0] + sizeof(MONOM *) and interpretes them as pointer to a MONOM structure. But you have an array of structs, not an array of pointers. Replace your expressions by (*ppoly)[i].power (and all the others accordingly of course) and that part will work. By the way that's excactly the difference of the two debugger statements you have mentioned.
Besides, look at my comments concerning the use of powerIndex
I have an integer array:
int num[20] = {1,1,5,5,1,1,5,9,2,2,6,1,1,2,5,5,1,3,6,2};
I want to copy the elements num into the following struct:
struct tuple
{
int p1;
int p2;
int p3;
int p4;
};
I am doing the following:
struct tuple *arr;
memcpy(&arr,&num,sizeof(num));
This does not seem to work, since I am encountering a segmentation fault later on in the code.
When I try to print the size:
printf("size of arr: %lu, size of arr[0]: %lu \n", sizeof(arr), sizeof(arr[0]));
I get the following:
size of arr: 8, size of arr[0]: 16
which is wrong, since the values should read:
size of arr: 80, size of arr[0]: 16
Therefore when I try to print, it seg faults:
for (i=0;i<sizeof(arr)/sizeof(arr[0]);++i)
printf("%d,%d,%d,%d\n", arr[i].p1,arr[i].p2, arr[i].p3, arr[i].p4);
Can someone assist me as to where I might be going wrong?
Several points to make here. Firstly:
struct tuple *arr;
memcpy(&arr,&num,sizeof(num));
arr is a pointer to a struct tuple; it is not a struct tuple, and it's size is the pointer size on your system (which is probably 8 bytes), not the same size as a struct tuple. When you do the memcpy, it's copying over the pointer to struct tuple, not a struct tuple instance.
Secondly, if you meant to copy to a struct tuple like this:
struct tuple aTuple;
memcpy(&aTuple,&num,sizeof(num));
Then you would have an actual instance of a struct tuple rather than just a pointer, and the memcpy would copy to that memory. But this would still be wrong because:
1) The size of the array is much larger than the size of struct tuple, and
2) Structures are not guaranteed to have all their fields adjacent in memory. There can be padding between p1 and p2, etc., so the structure and the array would be arranged in memory differently and not directly copyable.
Incidentally, this would work for memcpy to a struct tuple:
struct tuple aTuple;
aTuple.p1 = aTuple.p2 = aTuple.p3 = aTuple.p4 = 42;
struct tuple anotherTuple;
memcpy(&anotherTuple,&aTuple,sizeof(struct tuple));
I post that only as an example of correct usage.
EDIT:
Another thing, regarding this:
printf("size of arr: %lu, size of arr[0]: %lu \n", sizeof(arr), sizeof(arr[0]));
Did you pass num to another function, as parameter arr? In that case the arr is also a pointer, whose size is 8 rather than 80. When you pass an array to a function, it is passed as a pointer.
Try replacing struct tuple *arr; with struct tuple arr[5]; or perhaps struct tuple arr[sizeof(num)/sizeof(struct tuple)];. When you declare arr as a pointer, it doesn't allocate any space for the array it's pointing to. When you declare it as an array, it will decay to a pointer in the memcpy call and blit the int array over top of the stack-(or static-)allocated struct array.
Alternatively, you could initialize arr with a call to malloc(sizeof(num)), but be sure to match such a call with a call to free().
Also, as pointed out by comments, you need to pass arr and num rather than &arr and &num. You want to copy the data, not the pointers (although it may be that &num is equivalent to num as a pointer, in this case).
I've been getting back into C for something, but I'm having trouble remembering much of how this memory management works. I'd like to have a pointer to an array of pointers to structures.
Say I have:
struct Test {
int data;
};
Then the array:
struct Test **array1;
Is this correct? My issue is working with this thing. So each pointer in the array points to something that is allocated separately. But I think I need to do this first:
array1 = malloc(MAX * sizeof(struct Test *));
I am having trouble understanding the above. Do I need to do this, and why do I need to do this? In particular, what does it mean to allocate memory for pointers if I am going to be allocating memory for each thing that the pointer points to?
Say now I have pointer to an array of pointers to structures. I now want it to point to the same array that I've created earlier.
struct Test **array2;
Do I need to allocate room for pointers like I did above, or can I just do:
array2 = array1
Allocated Array
With an allocated array it's straightforward enough to follow.
Declare your array of pointers. Each element in this array points to a struct Test:
struct Test *array[50];
Then allocate and assign the pointers to the structures however you want. Using a loop would be simple:
array[n] = malloc(sizeof(struct Test));
Then declare a pointer to this array:
// an explicit pointer to an array
struct Test *(*p)[] = &array; // of pointers to structs
This allows you to use (*p)[n]->data; to reference the nth member.
Don't worry if this stuff is confusing. It's probably the most difficult aspect of C.
Dynamic Linear Array
If you just want to allocate a block of structs (effectively an array of structs, not pointers to structs), and have a pointer to the block, you can do it more easily:
struct Test *p = malloc(100 * sizeof(struct Test)); // allocates 100 linear
// structs
You can then point to this pointer:
struct Test **pp = &p
You don't have an array of pointers to structs any more, but it simplifies the whole thing considerably.
Dynamic Array of Dynamically Allocated Structs
The most flexible, but not often needed. It's very similar to the first example, but requires an extra allocation. I've written a complete program to demonstrate this that should compile fine.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct Test {
int data;
};
int main(int argc, char **argv)
{
srand(time(NULL));
// allocate 100 pointers, effectively an array
struct Test **t_array = malloc(100 * sizeof(struct Test *));
// allocate 100 structs and have the array point to them
for (int i = 0; i < 100; i++) {
t_array[i] = malloc(sizeof(struct Test));
}
// lets fill each Test.data with a random number!
for (int i = 0; i < 100; i++) {
t_array[i]->data = rand() % 100;
}
// now define a pointer to the array
struct Test ***p = &t_array;
printf("p points to an array of pointers.\n"
"The third element of the array points to a structure,\n"
"and the data member of that structure is: %d\n", (*p)[2]->data);
return 0;
}
Output:
> p points to an array of pointers.
> The third element of the array points to a structure,
> and the data member of that structure is: 49
Or the whole set:
for (int i = 0; i < 100; i++) {
if (i % 10 == 0)
printf("\n");
printf("%3d ", (*p)[i]->data);
}
35 66 40 24 32 27 39 64 65 26
32 30 72 84 85 95 14 25 11 40
30 16 47 21 80 57 25 34 47 19
56 82 38 96 6 22 76 97 87 93
75 19 24 47 55 9 43 69 86 6
61 17 23 8 38 55 65 16 90 12
87 46 46 25 42 4 48 70 53 35
64 29 6 40 76 13 1 71 82 88
78 44 57 53 4 47 8 70 63 98
34 51 44 33 28 39 37 76 9 91
Dynamic Pointer Array of Single-Dynamic Allocated Structs
This last example is rather specific. It is a dynamic array of pointers as we've seen in previous examples, but unlike those, the elements are all allocated in a single allocation. This has its uses, most notable for sorting data in different configurations while leaving the original allocation undisturbed.
We start by allocating a single block of elements as we do in the most basic single-block allocation:
struct Test *arr = malloc(N*sizeof(*arr));
Now we allocate a separate block of pointers:
struct Test **ptrs = malloc(N*sizeof(*ptrs));
We then populate each slot in our pointer list with the address of one of our original array. Since pointer arithmetic allows us to move from element to element address, this is straight-forward:
for (int i=0;i<N;++i)
ptrs[i] = arr+i;
At this point the following both refer to the same element field
arr[1].data = 1;
ptrs[1]->data = 1;
And after review the above, I hope it is clear why.
When we're done with the pointer array and the original block array they are freed as:
free(ptrs);
free(arr);
Note: we do NOT free each item in the ptrs[] array individually. That is not how they were allocated. They were allocated as a single block (pointed to by arr), and that is how they should be freed.
So why would someone want to do this? Several reasons.
First, it radically reduces the number of memory allocation calls. Rather then N+1 (one for the pointer array, N for individual structures) you now have only two: one for the array block, and one for the pointer array. Memory allocations are one of the most expensive operations a program can request, and where possible, it is desirable to minimize them (note: file IO is another, fyi).
Another reason: Multiple representations of the same base array of data. Suppose you wanted to sort the data both ascending and descending, and have both sorted representations available at the same time. You could duplicate the data array, but that would require a lot of copying and eat significant memory usage. Instead, just allocate an extra pointer array and fill it with addresses from the base array, then sort that pointer array. This has especially significant benefits when the data being sorted is large (perhaps kilobytes, or even larger, per item) The original items remain in their original locations in the base array, but now you have a very efficient mechanism in which you can sort them without having to actually move them. You sort the array of pointers to items; the items don't get moved at all.
I realize this is an awful lot to take in, but pointer usage is critical to understanding the many powerful things you can do with the C language, so hit the books and keep refreshing your memory. It will come back.
It may be better to declare an actual array, as others have suggested, but your question seems to be more about memory management so I'll discuss that.
struct Test **array1;
This is a pointer to the address of a struct Test. (Not a pointer to the struct itself; it's a pointer to a memory location that holds the address of the struct.) The declaration allocates memory for the pointer, but not for the items it points to. Since an array can be accessed via pointers, you can work with *array1 as a pointer to an array whose elements are of type struct Test. But there is not yet an actual array for it to point to.
array1 = malloc(MAX * sizeof(struct Test *));
This allocates memory to hold MAX pointers to items of type struct Test. Again, it does not allocate memory for the structs themselves; only for a list of pointers. But now you can treat array as a pointer to an allocated array of pointers.
In order to use array1, you need to create the actual structs. You can do this by simply declaring each struct with
struct Test testStruct0; // Declare a struct.
struct Test testStruct1;
array1[0] = &testStruct0; // Point to the struct.
array1[1] = &testStruct1;
You can also allocate the structs on the heap:
for (int i=0; i<MAX; ++i) {
array1[i] = malloc(sizeof(struct Test));
}
Once you've allocated memory, you can create a new variable that points to the same list of structs:
struct Test **array2 = array1;
You don't need to allocate any additional memory, because array2 points to the same memory you've allocated to array1.
Sometimes you want to have a pointer to a list of pointers, but unless you're doing something fancy, you may be able to use
struct Test *array1 = malloc(MAX * sizeof(struct Test)); // Pointer to MAX structs
This declares the pointer array1, allocated enough memory for MAX structures, and points array1 to that memory. Now you can access the structs like this:
struct Test testStruct0 = array1[0]; // Copies the 0th struct.
struct Test testStruct0a= *array1; // Copies the 0th struct, as above.
struct Test *ptrStruct0 = array1; // Points to the 0th struct.
struct Test testStruct1 = array1[1]; // Copies the 1st struct.
struct Test testStruct1a= *(array1 + 1); // Copies the 1st struct, as above.
struct Test *ptrStruct1 = array1 + 1; // Points to the 1st struct.
struct Test *ptrStruct1 = &array1[1]; // Points to the 1st struct, as above.
So what's the difference? A few things. Clearly, the first method requires you to allocate memory for the pointers, and then allocate additional space for the structs themselves; the second lets you get away with one malloc() call. What does the extra work buy you?
Since the first method gives you an actual array of pointers to Test structs, each pointer can point to any Test struct, anywhere in memory; they needn't be contiguous. Moreover, you can allocate and free the memory for each actual Test struct as necessary, and you can reassign the pointers. So, for example, you can swap two structures by simply exchanging their pointers:
struct Test *tmp = array1[2]; // Save the pointer to one struct.
array1[2] = array1[5]; // Aim the pointer at a different struct.
array1[5] = tmp; // Aim the other pointer at the original struct.
On the other hand, the second method allocates a single contiguous block of memory for all of the Test structs and partitions it into MAX items. And each element in the array resides at a fixed position; the only way to swap two structures is to copy them.
Pointers are one of the most useful constructs in C, but they can also be among the most difficult to understand. If you plan to continue using C, it'll probably be a worthwhile investment to spend some time playing with pointers, arrays, and a debugger until you're comfortable with them.
Good luck!
I suggest that you build this out a layer at a time using typdefs to create layers of types. By doing so, the different types needed will be much clearer.
For instance:
typedef struct Test {
int data;
} TestType;
typedef TestType * PTestType;
This will create two new types, one for the struct and one for a pointer to the struct.
So next if you want an array of the structs then you would use:
TestType array[20]; // creates an array of 20 of the structs
If you want an array of pointers to the structs then you would use:
PTestType array2[20]; // creates an array of 20 of pointers to the struct
Then if you want to allocate structs into the array you would do something like:
PTestType array2[20]; // creates an array of 20 of pointers to the struct
// allocate memory for the structs and put their addresses into the array of pointers.
for (int i = 0; i < 20; i++) {
array2 [i] = malloc (sizeof(TestType));
}
C does not allow you to assign one array to another. You must instead use a loop to assign each element of one array to an element of the other.
EDIT: Another Interesting Approach
Another approach would be a more object oriented approach in which you encapsulate a few things. For instance using the same layers of types we create two types:
typedef struct _TestData {
struct {
int myData; // one or more data elements for each element of the pBlob array
} *pBlob;
int nStructs; // count of number of elements in the pBlob array
} TestData;
typedef TestData *PTestData;
Next we have a helper function which we use to create the object, named appropriately enough CreateTestData (int nArrayCount).
PTestData CreateTestData (int nCount)
{
PTestData ret;
// allocate the memory for the object. we allocate in a single piece of memory
// the management area as well as the array itself. We get the sizeof () the
// struct that is referenced through the pBlob member of TestData and multiply
// the size of the struct by the number of array elements we want to have.
ret = malloc (sizeof(TestData) + sizeof(*(ret->pBlob)) * nCount);
if (ret) { // make sure the malloc () worked.
// the actual array will begin after the end of the TestData struct
ret->pBlob = (void *)(ret + 1); // set the beginning of the array
ret->nStructs = nCount; // set the number of array elements
}
return ret;
}
Now we can use our new object as in the source code segment below. It should check that the pointer returned from CreateTestData() is valid however this is really just to show what could be done.
PTestData go = CreateTestData (20);
{
int i = 0;
for (i = 0; i < go->nStructs; i++) {
go->pBlob[i].myData = i;
}
}
In a truly dynamic environment you may also want to have a ReallocTestData(PTestData p) function that would reallocate a TestData object in order to modify the size of the array contained in the object.
With this approach, when you are done with a particular TestData object, you can just free the object as in free (go) and the object and its array are both freed at the same time.
Edit: Extending Further
With this encapsulated type we can now do a few other interesting things. For instance, we can have a copy function, PTestType CreateCopyTestData (PTestType pSrc) which would create a new instance and then copy the argument to a new object. In the following example, we reuse the function PTestType CreateTestData (int nCount) that will create an instance of our type, using the size of the object we are copying. After doing the create of the new object, we make a copy of the data from the source object. The final step is to fix up the pointer which in the source object points to its data area so that pointer in the new object now points to the data area of itself rather than the data area of the old object.
PTestType CreateCopyTestData (PTestType pSrc)
{
PTestType pReturn = 0;
if (pSrc) {
pReturn = CreateTestData (pSrc->nStructs);
if (pReturn) {
memcpy (pReturn, pSrc, sizeof(pTestType) + pSrc->nStructs * sizeof(*(pSrc->pBlob)));
pReturn->pBlob = (void *)(pReturn + 1); // set the beginning of the array
}
}
return pReturn;
}
Structs are not very different from other objects. Let's start with characters:
char *p;
p = malloc (CNT * sizeof *p);
*p is a character, so sizeof *p is sizeof (char) == 1; we allocated CNT characters. Next:
char **pp;
pp = malloc (CNT * sizeof *pp);
*p is a pointer to character, so sizeof *pp is sizeof (char*). We allocated CNT pointers. Next:
struct something *p;
p = malloc (CNT * sizeof *p);
*p is a struct something, so sizeof *p is sizeof (struct something). We allocated CNT struct somethings. Next:
struct something **pp;
pp = malloc (CNT * sizeof *pp);
*pp is a pointer to struct, so sizeof *pp is sizeof (struct something*). We allocated CNT pointers.
I am new to C, and things are different in C than in any other language I've learned. In my homework I want to create an array of chars which point to an array of chars, but rather than make a multidimensional char array, I figure I'd have more control and create char arrays and put each individual one into the indexes of the original char array:
char keywords[10];
keywords[0] = "float";
The above example is to clarify and a simple case. But my question is due to the research I've been doing, and I am confused about something. Normally this would work in other languages, but in C it would be:
char *keyword[10];
keywords[0] = "float";
But when I want to send it through a function, why is this necessary:
void function(char **keyword); //function prototype
Wouldn't just passing the array pointer be enough?
It looks like you're confused by the double stars in
void function(char ** keyword);
The double stars just means that this function expects you to pass a pointer to a pointer to a char. This syntax doesn't include any information about the fact that you are using an array, or that the char is actually the first char of many in a string. It's up to you as the programmer to know what kind of data structure this char ** actually points to.
For example, let's suppose the beginning of your array is stored at address 0x1000. The keyword argument to the function should have a value of 0x1000. If you dereference keyword, you get the first entry in the array, which is a char * that points to the first char in the string "float". If you dereference the char *, you get the char "f".
The (contrived) code for that would look like:
void function(char **keyword)
{
char * first_string = *keyword; // *keyword is equivalent to keyword[0]
char first_char = *first_string; // *first_string is equivalent to first_string[0]
}
There were two pointers in the example above. By adding an offset to the first pointer before dereferencing it, you can access different strings in the array. By adding an offset to the second pointer before dereferencing it, you can access different chars in the string.
char *keyword[10];
keyword is an array 10 of char *. In a value context, it converted to a pointer to a char *.
This conversion is a part of what Chris Torek calls "The Rule":
"As noted elsewhere, C has a very important rule about arrays and pointers. This rule -- The Rule -- says that, in a value context, an object of type ‘array of T’ becomes a value of type ‘pointer to T’, pointing to the first element of that array"
See here for more information: http://web.torek.net/torek/c/pa.html
The C-FAQ also has an entry on this array to pointer conversion:
Question 6.3: So what is meant by the "equivalence of pointers and arrays'' in C?
http://c-faq.com/aryptr/aryptrequiv.html
In C, you can't really pass array to a function. Instead, you pass a pointer to the beginning of the array. Since you have array of char*, the function will get a pointer to char*, which is char**.
If you want, you can write (in the prototype) char *keyword[] instead of char **keyword. The compiler will automatically convert it.
Also, in C you can dereference pointers like arrays, so you loose almost nothing with that "converting to pointer".
If you want to
void function(char **keyword);
Andy, think about that an array is just a pointer(to the beginning of the array), that's why you write:
void function(char **keyword);
Because you have create an array to char pointers.
If it's easier to understand try:
void function(char *keyword[]);
But it's more C standard to use the first one, though if you use a C++ compiler won't really matter.
Here is the answer.
#include<stdio.h>
int main(void)
{
char *CharPtr[3];
char a[4]="abc";
char b[4]="def";
char c[4]="ghi";
CharPtr[0]=a;
CharPtr[1]=b;
CharPtr[2]=c;
printf("\n content of CharPtr[0] =%s",CharPtr[0]);
printf("\n content of CharPtr[1] =%s",CharPtr[1]);
printf("\n content of CharPtr[2] =%s\n",CharPtr[2]);
printf(" \n content of char a[4]=%s",a);
printf(" \n content of char b[4]=%s",b);
printf(" \n content of char c[4]=%s\n",c);
}
char *keywords[10] is an array of character pointers. So keywords[0], keywords[1].. and so on will have the addresses to different character arrays.
In printf you can use %s and keywords[0] to print the entire character array whose address(i.e. address of the first byte in the array) is stored at keywords[0].
While passing to a function, if you give *keywords, you are referring to the value at(address stored at keywords[0]) which is again an address. So, to get the value instead of address, you can add another *... Hope that clarifies a bit..
I am assuming that you are assigning your first string:
"float"
to the first index position of keyword[0]
char keyword[0] = "float";
which is the first index position of the array:
char keyword[10];
If the previous is the case, then in a sense, you are essentially creating a data structure that holds a data structure. The array of any type is the 'smallest' data structure of that type in C. Considering that in your example you are creating a character array, then you are actually utilizing the smallest data type (char=1bit) at each index position of the smallest built in data structure (the array).
With that said, if in your example, you are attempting to create an array of arrays; your character array
/* Hold ten characters total */
char keyword[10];
was designed to hold 10 characters. One at each index position (which you probably already know). So after declaring the array titled keyword, you then try to initialize the first index position of the array with another (the second) character array:
/* I believe this is what you had stated */
char keywords[0] = "float";
With the second character array having an index of 5 positions in size.
In order to achieve your desired goal, you would essentially be creating an array that basically emulates the effect of a data structure that 'holds' other data structures.
NOTE: If you had/have plans on trying to create a data structure that holds a data structure that holds a data structure. A.K.A. a triple nested data structure and in this case I think that would be a Matrix, WHICH I WOULDN'T RECOMMEND!
None the less, the matrix structure would be in the form of the first index position of keyword, being assigned the whole array of keywords, which would include all of the data stored in each index position of the keywords array. Then there would something probably like: keywords1, keywords2, ... keywords9,
which would essentially emulate the form of:
char *keyword[10] = {
char *keywords0[10] = {"float", etc, etc, etc.};
char *keywords1[10] = {"keyword1", "secondIndexOfThisArray", etc, etc, etc.};
and so
};
So basically from right to left, the keyword array, is an array of pointers that points to array of pointers that points to character arrays.
If that is what you are representing you would be better defining a custom data type of struct/record, and with in that custom structure you would want to define a subordinate or child level of structures. You could also pre-declare them then initialize them.
e.g.
typedef *nestedDataStructures {
struct keyWords[];
struct keyWords1[];
struct keyWords2[];
... and so on.
}; nestedDataStructures
Instead of adding ten structs to one custom structure I would break down into 3 or 4 (how ever many structures and use) and create a module in order to yield symmetrical layers of abstraction as you manipulate your data set.
None the less, you can not create the character array and potentially assign the other character array in the fashion that you did (or who knows maybe you can), but the way you would want to emulate the array that holds arrays, is to create a character pointer array up front, of X number index positions and then initialize then use the character arrays in the form of a strings declared with in the initialization of the original declaration.
So basically you could declare your whole array upfront, then with in your program design, either dereference each index position, use assignment, or print/write the index position.
Like for instance you could always do something like this:
/* Example of the program and declaration with out a function */
#include <stdio.h>
int main(){
/*
* A character pointer array that contains multiple
* character arrays.
*/
char *grewMe[2] = {"I want to ", "grow to be bigger"};
int w = 0;
for(; w < 2;) {
printf("%s", grewMe[w]);
++w;
}
printf(" :-)\n");
w = 0;
return 0;
}
// Output:
// I want to grow to be bigger :-)
Or something like this:
/* Example of program: function passed arguments
* of a pointer to the array of pointers
*/
#include <stdio.h>
void mygrowth(char *growMe[]);
int main(){
char *growMe[2] = {"I want to ", "grow to be bigger"};
mygrowth(growMe);
printf(" :-)\n");
return 0;
}
void mygrowth(char *growMe[])
{
int w = 0;
for (; w < 2;) {
printf("%s", growMe[w]);
++w;
}
}
The assignment of each index position as it's passed as an argument:
/*
* This program compiles, runs and outputs properly
* Example of a program with a function of
* arguments pnt2pnter
*/
#include <stdio.h>
#include <stdlib.h>
void thoughtAsAFunction(char **iThink);
int main()
{
char *iThink[10] = {"I am trying to grow, but it's a hard task to ",
"accomplish. My father is short ",
"my mother is even shorter than him, ",
"what is the probability of me getting taller? ",
"Well both my grandfather's were Six ",
"Foot Five, and both my grandmother's ",
"were over 5 foot 8 inches tall! If my ",
"grandparent's genes point to my parents, and my ",
"parent's genes point to mine I might have a chance ",
"of being 6 foot. Do you know what I mean? "};
thoughtAsAFunction(iThink);
printf(":-)\n");
return 0;
}
void thoughtAsAFunction(char **iThink) {
int andy = 0;
for (; andy < 10;) {
char * pntThroughPnt = iThink[andy];
printf("%s", pntThroughPnt);
++andy;
}
andy = 0;
}
Or pass by reference, with an increment of the loop count variable:
/*
* This program compiles, runs, and outputs all of the character
* arrays.
*
*/
#include <stdio.h>
#include <stdlib.h>
void thoughtAsAFunction(char **iThink);
int main()
{
char *iThink[10] = {"I am trying to grow, but it's a hard task to ",
"accomplish. My father is short ",
"my mother is even shorter than him, ",
"what is the probability of me getting taller? ",
"Well both my grandfather's were Six ",
"Foot Five, and both my grandmother's ",
"were over 5 foot 8 inches tall! If my ",
"grandparent's genes point to my parents, and my ",
"parent's genes point to mine, then I might have a chance ",
"of being 6 foot. Do you know what I mean? "};
int andy = 0;
for (; andy < 10;) {
// pass by reference and increment.
thoughtAsAFunction(&iThink[andy]);
++andy;
}
printf(":-)\n");
andy = 0;
return 0;
}
void thoughtAsAFunction(char **iThink) {
char * pntThroughPnt = *iThink;
printf("%s", pntThroughPnt);
}
Keep in mind that this is the case if you declare the array of pointers (char *array[10];), and each pointer points to an array of characters.