The following code sample demonstrates the similarities between pointers and arrays. In the second method, the author declares cur_name as a pointer to a pointer. My question is, why is this necessary? Why does he declare a new pointer instead of just using the original pointer, names? I should note, the code compiles and runs fine when I get rid of cur_name and use names, so is it a matter of style rather than function? Any explanation would be appreciated.
#include <stdio.h>
int main(int argc, char *argv[])
{
// create two arrays we care about
int ages[] = {23, 43, 12, 89, 2};
char *names[] = {"Alan", "Frank", "Mary", "John", "Lisa"};
// safely get the size of ages
int count = sizeof(ages) / sizeof(int);
int i = 0;
// first way using indexing
for(i = 0; i < count; i++) {
printf("%s has %d years alive.\n",
names[i], ages[i]);
}
printf("---\n");
// setup the pointers to the start of the arrays
int *cur_age = ages;
char **cur_name = names;
// second way using pointers
for(i = 0; i < count; i++) {
printf("%s is %d years old.\n",
*(cur_name+i), *(cur_age+i));
}
printf("---\n");
// third way, pointers are just arrays
for(i = 0; i < count; i++) {
printf("%s is %d years old again.\n",
cur_name[i], cur_age[i]);
}
printf("---\n");
// fourth way with pointers in a stupid complex way
for(cur_name = names, cur_age = ages;
(cur_age - ages) < count;
cur_name++, cur_age++)
{
printf("%s lived %d years so far.\n",
*cur_name, *cur_age);
}
return 0;
}
The code uses a pointer to a pointer to represent a pointer into an array of C strings. Namely, cur_name is a pointer into the array of C strings called names. Since a string in C is itself represented by a pointer to char, a pointer into the array of such pointers becomes a pointer to a pointer.
Why does he declare a new pointer instead of just using the original pointer, names?
Because names is not a pointer, it is an array of pointers (see the square brackets after the declaration? That is what makes names an array. The single asterisk in front is related to the type of the array element, which is a char* in this program).
Making an array adds a level of indirection: to point into an array of ints you need int*, but to point into an array of int* you need an int** pointer.
If you have an array of type T as below
T a[N];
then if you want to define a pointer to its first element you have to write
T *p = a;
Now substitute T for the type of elements of array names defined as
char *names[] = {"Alan", "Frank", "Mary", "John", "Lisa"};
You will get
typedef char * T;
T names[] = {"Alan", "Frank", "Mary", "John", "Lisa"};
so the pointer to the first element of the array will look like
T *cur_name = names;
If you now will make the reverse substitution you will get
char * *cur_name = names;
^^^^^^
T
The author does increment them in the fourth method, so he needs the temporaries for that, but you are correct about it not being necessary in the second method. Perhaps (s)he is using the assignment to show their equivalence?
I think the examples would be clearer if each method was implemented in its own function.
Related
I tried this following code but it clearly didn't work:
void main3()
{
int n;
printf("Input the dimension of the array");
scanf("%d", &n);
int* testMatrix2 = malloc(sizeof(int) * n);
testMatrix2 = {512, 51, 642}; //is there a way to do this? "expected an expression" error
}
As the comment shows, is there a way to initialize an array as you would normally do without using arrays? I know it's a risky move, but it would make my life easier during testing.
The use of for cycles would not be feasible for me as I need a sort of randomness in the array.
As #EugeneSh. stated it is not possible for any size array. If the array has a fixed size you can wrap it into the structure:
typedef struct
{
int x[10];
}wrappedArray;
void foo(void)
{
wrappedArray *wa = malloc(sizeof(*wa));
*wa = (wrappedArray){1,2,3,4,5,6,7,8,9,10};
}
Arrays are "non-modifiable" L-values. Therefore they cannot be assigned with = operator.
However, you could memcpy from a compound literal.
memcpy(testMatrix2, (const int[]){512, 51, 642}, sizeof(int[3]));
Just ensure that n >= 3 before doing this to avoid Undefined Behavior.
As the other post already shown how to copy array to dynamically allocated space. Just in case if you don't need to access the array in some other function (or out of scope), then no need to allocate space dynamically. You can use compound literal:
#include <stdio.h>
int main (void) {
int* testMatrix2 = (int []){512, 51, 642};
for (int i = 0; i < 3; ++i) {
printf ("%d ", testMatrix2[i]);
}
printf ("\n");
return 0;
}
Output:
# ./a.out
512 51 642
Compound literals Constructs an unnamed object of specified type in-place.
In this statement of above program
int* testMatrix2 = (int []){512, 51, 642};
(int []){512, 51, 642} is a compound literal. It will create an unnamed automatic array of type int [3], initialise the array to the value 512, 51 and 642 and the pointer to first element of this array object will be assigned to testMatrix2.
This question already has answers here:
What is array to pointer decay?
(11 answers)
In C, are arrays pointers or used as pointers?
(6 answers)
Closed 4 years ago.
I'm attempting to learn C and going through the K&R book. Many examples online seem to use pointers to return a value from a function. I would think then that the same would be used for this K & R function:
/*
Reverse a string in place
*/
void reverse(char s[])
{
int c, i, j;
for (i = 0, j = strlen(s) - 1; i < j; i++, j--)
{
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
int main()
{
char s[] = "HELLO";
reverse(s);
printf("%s", s);
return (0);
}
I would think that the string would NOT be reversed in this situation. Yet it prints the char array backwards as originally intended by the author.
How does it do that? I don't completely understand pointers yet but I was thinking it would be like reverse(&s) and then void reverse(char *s[]) {...}
Arrays, when passed as arguments to functions, decay to a pointer to their first element. Hence when you pass an any type of array (including a string) into a function, you are effectively passing it by reference and any modifications made to the array within the function will be reflected in the calling code as well, after the function call.
Examine the output of this code to enrich your understanding of pointers and arrays:
#include <stdio.h>
#include <stdlib.h>
void foo(int *arg, size_t len)
{
size_t i;
printf("sizeof arg is %zu\n", sizeof arg);
for(i = 0; i < len; i++)
{
printf("arg[%zu] = %d\n", i, arg[i]);
}
printf("arg's address is %p\n", (void *) arg);
}
int main()
{
int array[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
printf("sizeof array is %zu\n", sizeof array);
printf("array begins at %p in memory\n", (void *) array);
foo(array, 10);
return 0;
}
Since no copy of the string is made anywhere the original string must be modified by the array assignments in reverse. Changing void reverse(char s[]) to void reverse(char *s) would change nothing. An array of unknown size behaves just like a pointer to the array's first element.
I also learned C from K&R, it's one of the best books out there, although after reading it, get a book that covers C99 and C11.
If you look at section 5.3 in the book
5.3 Pointers and Arrays
They write:
When an array name is passed to a function, what is passed is the
location of the initial element. Within the called function, this
argument is a local variable, and so an array name parameter is a
pointer, that is, a variable containing an address.
So although arrays and pointers are different, when you pass an array to a function it does not pass the array, but a pointer to the first element.
some differences:
There is one difference between an array name and a pointer that must
be kept in mind. A pointer is a variable, so pa=a and pa++ are legal.
But an array name is not a variable; constructions like a=pa and a++
are illegal.
One thing to keep in mind about K&R book when you read it. They mention something once, and 50 pages later they use it, unless you remember it, it will look like it came out of nowhere. They don't repeat themselves much in the book.
The array will implicitly be converted to a pointer to the first element of the array when passed as an argument to a function.
That is why the the elements of the original array are modified and not a copy of it since no copy of the array is made; only the address of the first element.
I practiced today some C code, especially array with return function and pointers.
And I found some code which were really confusing and want to know why it is.
So I have first a function which print all elements out of the array.
void function(int *arr)
{
...
printf("%d, arr[i]);
}
Now in main I have a 2D array and a 1D array.
int array2D[2][2] = {{1,2}, {3,4}};
int array1D[3] = {1,2,3};
function(*array2D); // Why do I need here the derefernce pointer
function(array1D); // why I don't need here the deference pointer
And in another case:
void disp( int *num)
{
printf("%d ", *num);
}
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
for (int i=0; i<10; i++)
{
/* Passing addresses of array elements*/
disp(&arr[i]); // why i need here & and above in the function not
}
}
This is really confusing me right now. Can someone explain me this?
The first line
function(*array2D);
is equivalent to
function(array2D[0]);
So you are passing the first array [1,2]. In C an array decays into a pointer
when it is passed to a function.
However, your function function1 should also get the number of
elements of the array.
void function(int *arr, size_t len)
{
size_t i;
for(i = 0; i < len; ++i)
printf("%d\n", arr[i]);
}
Then you can call it2
int array2D[2][2] = { { 1,2} ,{3,4}};
int array1D[3] = {1,2,3};
function(*array2D, sizeof *array2D / sizeof **array2D);
function(array1D, sizeof array1D / sizeof *array1D);
disp (&arr[i]); // why i need here & and above in the function not
Because arr[i] would give you the value stored at the position i, disp
expects a pointer, so you use the &-operator which returns the address of the
array at the position i, which is also equivalent to arr + i.
1Don't call your functions function. Technically that is valid name, but it
would be better if you give your function more explicit names so that just by
reading the name, you know what the functions does.
2Note that sizeof array / sizeof *array only works with arrays. If you have a
function and you expect an array, you will get only a pointer to the array.
In this case you also would need to pass the length of the array.
We're used to the fact that int mike[10] decays to int *, which points to the first thing in the array. So it seems like int sam[5][10] might also decay to int * pointing to the first element of the array. But int sam[5][10] is not a "two-dimensional array of int" that decays to an int pointer, it's an array of five arrays of ten integers. The first thing in sam is the first of the five arrays, so sam decays to a pointer to an array of ten integers, which type is written int (*)[10], though it rarely is written.
So your array2D decays to a different type than integer pointer, which is why your call function(array2D); creates a type mismatch. But your call function(*array2D); does work because (as noted above) *array2D is the same as array2D[0], which is an array of integers, and does decay to int *.
For your second case, arr is an array, but arr[i] is an int, since it is just one position in the array. The ampersand operator makes a pointer of what it operates, so &arr[i] is a pointer, and the call works.
I have been learning arrays, but theres one thing that I cant figure out.
I borrowed two books for C and looked online, but found no solution.
My function timesTen multiplies every array elemenet that I have by 10,
then returns pointer of that array back function main()
How can I copy array a[2] directly in array x[2]?
I would usually use for loop, but I cant, because arguments are in two different functions.
Solution has probably got something to do with pointers, so feel free to post sollution here, but is there any way around them aswell?
Heres the source code:
#include <stdio.h>
int timesTen(int a[])
{
int i;
for (i=0;i<2;i++)
{
printf("%d\t", a[i]);
a[i]*=10;
printf("%d\n", a[i]);
}
return a;
}
int main()
{
int i;
int x[2];
int a[2]={10,50};
// i know here's an error, but how do I fix it? I cant put x[0]=timesTen(a[0])
x[2] = timesTen(a);
//also what if there is array a[10], and I want to copy it in x[5]
for (i=0;i<2;i++)
printf("%d\n", x[i]);
return 0;
}
Thanks!
What you need to understand is the distinction between arrays and pointers. When you declare your two arrays in main(), you allocate two times memory for two integers. That's fine. But in C, you simply cannot pass arrays around (as in: implicitly allocate a new slap of memory and copy the data of the source array into this memory region). Instead, any array identifier will decay to a pointer to the first element of the array in almost all situation. So when you write
int x[2];
int a[2]={10,50};
timesTen(a);
this code is precisely equivalent to
int x[2];
int a[2]={10,50};
timesTen(&a[0]);
So, why does that not clash with your declaration of timesTen()? Because array parameters in function declarations decay right there, on the spot, into a pointer! So, your function declaration is precisely equivalent to this one:
int timesTen(int* a) {
This is one of the least understood features of the C language, and admittedly, it is hard to wrap your brain around this, but once you understand what pointer decay means, you will be much more at ease using pointers and arrays.
So, back to your question. Since you passed only a pointer to your array to timesTen(), and since you modify this array, the changes are directly visible in main(). There are two ways to achieve the behavior you want:
You can change the definition of timesTen() to copy the data into a destination array:
void timesTen(int size, int* source, int* dest) {
for(int i = 0; i < size; i++) dest[i] = 10*source[i];
}
int main() {
int x[2];
int a[2]={10,50};
timesTen(2, a, x); //pointer decay!
//x now contains {100, 500}
}
You can copy the data into the destination array before calling your function to modify the destination array:
void timesTen(int size, int* data) {
for(int i = 0; i < size; i++) data[i] = 10*data[i];
}
int main() {
int x[2];
int a[2]={10,50};
memcpy(x, a, sizeof(a)); //the sizeof operator is one of only two places where no pointer decay happens!
timesTen(2, x); //pointer decay!
//x now contains {100, 500}
}
In the function timesTen, since a is an array, each modification made to it in the function is also done to the parameter you passed (call by address not by value). Therefore you don't need to returns anything.
void timesTen(int a[])
{
int i;
for (i=0;i<2;i++) a[i]*=10;
}
And you just call it by:
timesTen(a);
You probably want something like this:
timesTen(a);
memmove(x, a, 2 * sizeof(x[0]));
instead of
x[2] = timesTen(a);
Note that your function does not need to return anything, because it is modifying the array on its original place. In C if you have an array parameter, it means that only a pointer is passed, not the whole array.
in main function:
int *p;
int i;
p = timesTen(a);
for ( i = 0; i < 2; i++ )
{
printf( "%d\n",*(p + i)); // here you can print the values returned from your function
}
Through pointers you could have eaisly managed it
main ()
{
int a[ 2 ];
int *ptr = timesTen(a);
for ( int i=0; i<2 ; i++)
{
printf("%d",ptr[i]);
}
And as far as
x[2] = timesTen(a);
Is concerned note that x[2] will give "value at 2nd adress from adrees of base that is x"
And it is not a variable but it is a value and you cant assign to a value.
Technically x[2] is not a lvalue.
This question already has answers here:
How can I get the size of an array from a pointer in C?
(16 answers)
Closed 9 years ago.
For the following scenario, how can I get the size (3) of the array a via the pointer c? What is the pattern for solving this sort of problems?
struct struct_point {
int x;
int y;
int z;
};
typedef struct struct_point point;
int test_void_pointer () {
point a[3] = {{1, 1, 1}, {2, 2, 2}};
void * b;
point * c;
b = a;
c = b;
/* get_size_p (c) */
}
You can't. The pointer is just an address, a number, and it doesn't hold any information about the data it points to except its type.
Side note: that's why they say "arrays decay to pointers". They "decay" because inherently a pointer holds less information compared to an array.
As nims points out in the comments when passing an array to a function, it automatically decays to a pointer to the first element - and doing sizeof in the function doesn't yield the expected result. Incidentally there's also a C FAQ about this.
In C, no information about the size of the array is stored with the array. You have to know how big it is to work with it safely.
There are a few techniques for working around this. If the array is declared statically in the current scope, you can determine the size as:
size_t size = (sizeof(a) / sizeof(a[0]);
This is useful if you don't want to have to update the size every time you add an element:
struct point a[] = {{1, 1, 1}, {2, 2, 2}};
size_t size = (sizeof(a) / sizeof(a[0));
But if you have an arbitrary array, that has been passed in from somewhere else, or converted to a pointer as in your example, you'll need some way of determining its size. The usual ways to do this are to pass the size in along with the array (either as a separate parameter, or as a struct containing the array), or if the array is of a type which can contain a sentinel value (a value of the given type that is not valid), you can allocate an array one bigger than you need add a sentinel to the end of the array and use that to determine when you've reached the end.
Here's how you might pass in a length as a separate argument:
struct point myfunction(struct point array[], size_t n) {
for (size_t i = 0; i < n; ++i) {
struct point p = array[i];
// do something with p ...
}
}
Or as a structure containing the length:
struct point_array {
size_t n;
struct point elems[];
}
struct point myfunction(struct point_array a) {
for (size_t i = 0; i < a.n; ++i) {
struct point p = a.elems[i];
// do something with p ...
}
}
It would probably be hard to use sentinel values with an array of struct point directly, as there is no obvious invalid value that is still of the same type, but they are commonly used for strings (arrays of char which are terminated by a '\0' character), and arrays of pointers which are terminated by a null pointer. We can use that with struct point by storing pointers to our structures rather than storing them inline in the array:
struct point *myfunction(struct point *a[]) {
for (size_t i = 0; a[i] != NULL; ++i) {
struct point *p = a[i];
// do something with p ...
}
}
There's a way to determine the length of an array, but for that you would have to mark the end of the array with another element, such as -1. Then just loop through it and find this element. The position of this element is the length.