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
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);
}
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".
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.