Returning array from function (C) - c

I'm extremely new to C programming, and am going through some tutorials. One thing that stumped me is with returning a pointer to an array. I've cut down the example from https://www.tutorialspoint.com/cprogramming/c_return_arrays_from_function.htm to best illustrate my point.
#include <stdio.h>
int * getRandom( ) {
static int r[10];
int i;
for ( i = 0; i < 10; ++i) {
r[i] = i;
printf( "r[%d] = %d\n", i, r[i]);
}
return r;
}
int main () {
int *p;
int i;
p = getRandom();
for ( i = 0; i < 10; i++ ) {
printf( "*(p + %d) : %d\n", i, *(p + i));
}
return 0;
}
As one would expect, this prints
r[0] = 0
r[1] = 1
r[2] = 2
r[3] = 3
r[4] = 4
r[5] = 5
r[6] = 6
r[7] = 7
r[8] = 8
r[9] = 9
*(p + 0) : 0
*(p + 1) : 1
*(p + 2) : 2
*(p + 3) : 3
*(p + 4) : 4
*(p + 5) : 5
*(p + 6) : 6
*(p + 7) : 7
*(p + 8) : 8
*(p + 9) : 9
But when you change
static int r[10];
to
int r[10];
it instead prints
r[0] = 0
r[1] = 1
r[2] = 2
r[3] = 3
r[4] = 4
r[5] = 5
r[6] = 6
r[7] = 7
r[8] = 8
r[9] = 9
*(p + 0) : 0
*(p + 1) : 1980517315
*(p + 2) : -1164399724
*(p + 3) : 4199040
*(p + 4) : 4199040
*(p + 5) : 2285568
*(p + 6) : 19
*(p + 7) : 6356668
*(p + 8) : 8
*(p + 9) : 6356940
and I have no idea why. The only thing I can think of is that for some reason the compiler is reading the array cells as different data types, but I doubt that's right.

The static keyword is used to "remember" the value of r in the next call. If you remove it, then the memory allocated for r is flushed when the function returns, so you're just returning garbage.

When you have static int r[10];, the memory for storing the array is allocated at compile-time, and everything works as expected.
When you instead have int r[10], you are allocating your array on the run-time stack frame, which becomes invalid when the function call returns, and then gets overwritten by the next function call, so you see garbage.

The reason is that when you call getRandom() without a static array declaration, the array falls out-of-scope once the getRandom() function returns. This means that your pointer may no longer 'point' to r, because r is essentially discarded.
In order to return from getRandom() correctly, you would need to dynamically allocate your memory using malloc, for example:
int * getRandom( ) {
int *r = NULL;
r = malloc(sizeof(int) * 10); /* Create room for 10 integers*/
if (r == NULL) {
printf("Error: Could not allocate space\n");
return NULL;
}
int i;
for ( i = 0; i < 10; ++i) {
r[i] = i;
printf( "r[%d] = %d\n", i, r[i]);
}
return r; /* Returns a pointer to r*/
}
int main () {
int *p;
int i;
p = getRandom();
if (p == NULL) {
/*Error state*/
return 1;
}
for ( i = 0; i < 10; i++ ) {
printf( "*(p + %d) : %d\n", i, *(p + i));
}
free(p); /* Free the memory we allocated*/
return 0;
}
Note how we must free the memory we allocated (otherwise we would have memory leaks). Also note that we must handle the NULL case, where we could not allocate the memory necessary.

Excepting by a few cases, an array in a expression always decays to the address of its first element.
This pointer is the value returned by the function.
The array itself, as an object living in memory, in general dies after the function execution finished.
So, the memory address pointed by the pointer that the function returned is not guaranteed to preserve the array, and it could have garbage instead.
The static declaration preserves the array object, but still your function have returned a pointer to the head of the array and not the array itself.
It is bad practice to return a pointer to an inner static object of a function,
because you are allowing to any user of your function to change the values of the array from outside of the function in umpredictable ways.
If you want to return a complete array, as a value, perhaps you should define a struct type containing an array field, in this way:
typedef struct { int sub[10]; } wrappedarray_t;
wrappedarray_t getRandom(void) {
wrappedarray_t r;
// sentences....
return r;
}
wrappedarray_t p = getRandom();
printf("0th element: %d\n", p.sub[0]);

because you're using a locally allocated piece of data; once the program goes out of scope, then all the data you saved to it is thrown out and it'll return garbage values.
In this situation, you can do two things:
either malloc() a pointer-array OR use the static array and return one of them.
ANOTHER option you can do is to put an array buffer in the function parameters so the data is copied to that buffer.

Related

Pointers to an Array In C

So my book is explaining me pointers to an array using ts example
#include <stdio.h>
int main()
{
int s[4][2] = {
{1234,56},{1212,33},{1434,80},{1312,78}
};
int(*p)[2];
int i, j, * pint;
for (i = 0; i <= 3; i++)
{
p = &s[i];
pint = (int*)p;
printf("\n");
for (j = 0; j<= 1; j++)
{
printf("%d ", *(pint + j));
}
}
return 0;
}
The output is Given as
1234 56
1212 33
1434 80
1312 78
No issue I am getting the same output.
My question is what was the need of using another pointer pint ?
Why can't we directly use P?
So When I tried to do it using P directly it didn't work
printf("%d ", *(p + j));
I got garbage values in output, Why is this happening?
I also tried printing p and pint they are the same.
Although p and pint have the same value, p + 1 and pint + 1 do not. p + 1 is the same as (char *)p + sizeof *p, and pint + 1 is the same as (char *)pint + sizeof *pint. Since the size of the object pointed to is different, the arithmetic gives different results.
The pointer p is declared like
int(*p)[2];
So dereferencing the pointer expression with the pointer in this call of printf
printf("%d ", *(p + j));
you will get the j-th "row" of the type int[2] of the two dimensional array that in turn will be implicitly converted to a pointer of the type int * that will point to the first element of the j-th "row".
So instead of outputting elements of each row you will output first elements of each row that moreover results in undefined behavior when i will be greater than 2.

Values are not getting assigned to continuous addresses

Why on compiling the below piece of code is giving runtime error?
#include<stdio.h>
int main()
{
int i;
int *p;
int a = 10;
p= &a;
printf("address of a = %x\n",p);
*(p + 0) = 5;
*(p + 1) = 6;
*(p + 2) = 7;
*(p + 3) = 8;
for(i=0; i < 4; i++)
{
printf("address = %x value = %x\n",(p+i),*(p+i));
}
return 0;
}
In this code i am assigning values to the address of variable named a after that starting from address of a the values (6,7,8) respectively are getting assigned to the next address of a consecutively.
*(p + 1) = 6;
p is an int* - meaning that when you increment it by one, it doesn't jump one byte forwards - it jumps sizeof(int) bytes forward (probably 4 bytes). If you want to assign to the bytes separately, cast the pointer to a char*:
*((char*)p + 1) = 6;
When you write code like *(p + 1) = 6; - your program is very likely to crash. Per the standard this is undefined behavior, in practice what usually really happens behind the scenes is that since p == &a and a is on the stack, p + 1 points to 4 bytes in the stack above a - which likely contains some random value like a stack canary or a return address - and you are corrupting this value.
These expressions:
*(p + 1) = 6;
*(p + 2) = 7;
*(p + 3) = 8;
Create pointers that are past the memory bounds of a which are then subsequently dereferenced. Reading memory past the bounds of an object (or even attempting to create such a pointer if it is not just past the object) triggers undefined behavior.
In this particular case it caused your program to crash, but there is no guarantee that will happen.
You should allocate that memory before accessing it. Try using malloc().
Your code should look like this:
#include<stdio.h>
int main()
{
int i;
int a = 10;
char *p= (char *)&a;
printf("address of a = %p\n",p);
for (i = 0; i < sizeof(a); ++i) {
*(p + i) = i + 5;
}
for(i = 0; i < sizeof(a); ++i) {
printf("address = %p value = %d\n", p + i, *(p + i));
}
return 0;
}
One solution is to define p as a pointer to char. Another approach is, as suggested in other answers, just cast p into a pointer to char before any arithmetic. When using pointer arithmetic, the number of bytes you "jump" is as the size of the pointed type. So, p + 1 will jump 4 bytes, in case int is 4 bytes. This is why you should use a pointer to char if you want to move one byte at a time.
In addition, your loops should run N times, where N in the number of bytes. So, my suggestion is to use sizeof.
Last thing, please note that in order to print an int you should use %d, and use %p to print pointers (i.e addresses).

passing 2D array pointer to function in C

I'm trying to pass the address of a 2D array to a function in C. I initialize the 2D array as:
const int N = 3;
char t[N][N];
I try to convert this into a char***:
char*** t_ptr = &t;
But it fails with a:
warning: initialization from incompatible pointer type
The function I want to receive the array has a prototype such as:
void f(char*** t, int N) { ... };
What am I doing wrong? Thank you.
This
char*** t_ptr = &t;
is wrong as compiler pointed because t is an two dimensional array, instead of triple pointer like char*** use pointer to an array to point to it. For e.g
char t[3][3] = { "ab","de","gh"}; /* total 3 1D array & each 1D array has 3 elements */
char (*t_ptr)[3] = t; /* t_ptr is a pointer to an array, pointing to 3 elements at a time */
And you can print t_ptr like
for(int index = 0; index < 3 ; index++) {
printf("%s\n",t_ptr[index]);
}
For reading c declarations, you can visit: https://cdecl.org/
Now using #Achal's example array:
#include <stdio.h>
#include <stdlib.h>
int main()
{
// t is a 2D array (not a VLA)
char t[3][3] =
{
{'a', 'b', '\0'},
{'d', 'e', '\0'},
{'g', 'h', '\0'}
};
printf("t is composed of 3 arrays of 3 characters each,\n");
printf("with the following addresses (on my machine):\n");
printf("--------------------------------------------------\n");
printf("%p, %p, %p\n", t[0], t[1], t[2]);
// ------------------------------------------------
// p is an array of 3 char pointers or char*
// Notice initialization
char* p[3] = {t[0], t[1], t[2]};
// following line of code will break, if no '\0' is encountered
// since %s requires a char* and a null terminator
printf("\nPrint strings using p:\n");
printf("------------------------\n");
printf("%s, %s, %s\n", *p, *(p + 1), *(p + 2));
// ------------------------------------------------
// q is a pointer to a char* or q has type char**
// Notice initialization of q (q points to p)
char** q = p;
printf("\nUsing q:\n");
printf("-----------\n");
printf("%s, %s, %s\n", *q, *(q + 1), *(q + 2));
// ---------------- printing characters individually
printf("\nIndividually:\n");
printf("---------------\n");
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
printf("%c ",
*(*(q + i) + j)
);
}
printf("\n");
}
// -----------------------------------------------
// r is a pointer to an array of size 3 containing char
// r advances three char at a time (r doesn't know the size of t)
char (*r)[3] = t; // this is the type of t
printf("\nUsing r:\n");
printf("---------------\n");
printf("%p, %p, %p\n", *r, *(r + 1), *(r + 2));
// to extract chars
printf("%c, %c", *(*(r + 0) + 0), *(*(r + 2) + 1));
// -----------------------------------------------
return EXIT_SUCCESS;
}
Output:
t is composed of 3 arrays of 3 characters each,
with the following addresses (on my machine):
--------------------------------------------------
000000000022FE2F, 000000000022FE32, 000000000022FE35
Print strings using p:
------------------------
ab, de, gh
Using q:
-----------
ab, de, gh
Individually:
---------------
a b
d e
Using r:
---------------
000000000022FE2F, 000000000022FE32, 000000000022FE35
a, h
Process returned 0 (0x0) execution time : -0.000 s
Press any key to continue.
char t[N][N];
is in fact the same as
char t[N * N];
in memory. A pointer to such an array would in both cases be of type char *.
char *** is a pointer to a pointer, that is a pointer to a char, whereas char * is a pointer to a char and that's how you pass array references in C: You pass them as a pointer to the first element of that array and this first element is a char.
C cannot retain the exact type or structure of an array as soon as you pass it to functions. In memory, a char array is just a bunch of memory filled with chars and all you can pass around is a pointer to that memory. If that memory is char [] or char [][] or even char [][][] plays no role, in memory all three are a block full of chars and the function would have to explicitly know the structure in memory, otherwise all char arrays will always be char [] for a function.
I strongly discourage C beginners to ever use multidimensional arrays. Instead of
char t[N][N];
char c = t[y1][x1];
t[y2][x2] = 'X';
use
char t[N];
char c = t[y1 * N + x1];
t[y2 * N + x2] = 'X';
As that's basically what the compiler will internally do anyway.
Note that multidimensional arrays in C are not x-y, but y-x, the first value is the row, the second on the column, please see this tutorial.
Whoever disbelieves what I just said, try out this code:
int main ( ) {
char a[5][5];
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
a[y][x] = x + 10 * y;
}
}
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
printf("%02d ", a[y][x]);
}
printf("\n");
}
printf("------\n");
char * a2 = (char *)a;
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
printf("%02d ", a2[y * 5 + x]);
}
printf("\n");
}
}
You can run it online, if you like, the output is identical. Also have a look at the assembly code the compiler generates for either loop (e.g. gcc -S) and you will see it's almost identical as even in the first case the compiler uses an add and a mul instruction to access the correct memory location within the array.

How do I use pointers correctly in my code?

Hello everyone I just started learning how to use pointers and I got stuck in my code. I need to write a code that modifies(corrects the uppercases and lowercases and finds out the year of every citizen) and sorts a list of citizens. For an example if the user entry is:
4 //just the number of citizens
lAna lanIc 1999
lana lanac 1999
laNa LaneC 1989
lAna lanOc 1999
the display must be :
18; Lanac, Lana
18; Lanic, Lana
18; Lanoc, Lana
28; Lanec, Lana
#include <stdio.h>
#include <string.h>
#include <ctype.h>
typedef struct {
char name[26];
char surname[26];
int birth;
} citizen; //the structer for the citizen
void modify(citizen *g);
int compare(citizen g1, citizen g2); //compares citizens by birth or surname or name
void sort(citizen g[], int); //insertion sort
int main()
{
int n, i;
citizen g[100];
scanf("%d", &n);
for(i = 0; i < n; i++) {
scanf("%s %s %d", g[i].name, g[i].surname, &g[i].birth);
modify(g + i);
}
sort(g, n);
for (i = 0; i < n; i++) {
printf("%2d; %s %s\n", g[i].birth, g[i].surname, g[i].name);
}
return 0;
}
void modify(citizen *g) { //here I'm having trouble
int i = 0;
//trying to correct the name
if(isalpha(*g[i].name[0])) {
*g[i].name[0] = toupper(*g[i].name[0]);
}
for(i = 1; i < strlen(*g[i].name); i++) {
*g[i].name = toupper(*g[i].name);
}
//then the surname
if(isalpha(*g[i].surname[0])) {
*g[i].surnma[0] = toupper(*g[i].surname[0]);
}
for(i = 1; i < strlen(*g[i].surname); i++) {
*g[i].surname = toupper(*g[i].surname);
}
*g[i].birth = 2017 - *g[i].birth; //finding how old is the citizen
}
int compare(citizen g1, citizen g2) {
if(g1.birth == g2.birth) {
if(!strcmp(g1.surname, g2.surname)) {
return strcmp(g1.name,g2.name);
}
else {
return strcmp(g1.surname, g2.surname);
}
}
else if (g1.birth > g2.birth) {
return 1;
}
return -1;
}
void sort(citizen g[], int n) { //insertion sort
int i, j;
citizen tmp;
for(i = 0; i < n; i++) {
tmp = g[i];
j = i;
while(j > 0 && compare(g[j-1], tmp)) {
g[j] = g[j - 1];
j--;
}
g[j] = tmp;
}
}
The basics:
In your main function this:
citizen g[100];
declares an array of 100 citizens. g is an array which is not a pointer.
In your modify function
modify(citizen *g)
g is a pointer to a citizen. It is not an array. So you're probably asking why it is legal to do this:
modify(g + i);
The reason is that, in the context of using g in an expression, it is transformed by the compiler into a pointer to its first element. We say "g decays to a pointer to its first element".
There are two ways to access the thing(s) that a pointer points to (we say "dereference the pointer"). The first is to use the * operator. If p is int* we can do
int x = *p;
If p points to an int that is in an array of ints, we can do pointer arithmetic. So we could do
int y = *(p + 3);
int z = *(p - 2);
If p points to the third element of an array that is at least size 6, y now has the same value as the sixth element and z has the same value as the first element.
The second way to dereference a pointer is to use subscript syntax. The syntax p[i] is exactly equivalent to *(p + i) and I mean exactly. Addition is commutative so p + i == i + p which means *(p + i) == *(i + p) which means (and this is legal in C) p[i] == i[p] Anyway each of the statements above can be written using subscripts
int x = p[0];
int y = p[3];
int z = p[-2];
Except to save our sanity, we tend to only use subscript syntax if p is a pointer to the first element of an array or the first element of a malloc'd block.
If p is a pointer to a struct (like your citizen struct, you can access the fields in the struct by dereferencing p and using the normal diot syntax.
int myBirth = (*p).birth;
The parentheses are necessary because the dot operator normally has higher precedence than the * operator. With *p.birth the C compiler thinks that p s a struct with a field called birth which it tries to dereference as a pointer. C provides a shortcut syntax for the (*p).birth thing which is
int myBirth = p->birth; // Exactly equivalent to (*).birth
Finally in C, you can obtain a pointer to an arbitrary object with the & operator.
int x = 0;
int* p = &x; // p is a pointer to x.
So when we say g decays to a pointer to its first element, what we mean is that the compiler transforms
modify(g + i);
to
modify(&g[0] + i);
So, you see, your modify function receives a pointer to an element of g. Looking at the first couple of lines of the function:
if(isalpha(*g[i].name[0])) {
*g[i].name[0] = toupper(*g[i].name[0]);
}
Because i is 0 at this point, `g[i].name` is the same as `(*g).name` or `g->name`. Use the last one for clarity. The `name` field is an array of chars, so `name[0]` is the first character of the name, which is what you want. You have an extra dereference with the leading * that you don't need. The above should be
if (isalpha(g->name[0])) {
g->name[0] = toupper(g->name[0]);
}
Except toupper does the isalpha check for you, so all that becomes
g->name[0] = toupper(g->name[0]);
I'll leave it to you to fix the rest of the function, except to mention the rather bad bug here:
for(i = 1; i < strlen(*g[i].surname); i++) {
*g[i].surname = toupper(*g[i].surname);
}
This actually makes no sense to me at all.
Instead of dereference pointer your way, I will give you answer here:
void modify(citizen *g) { //here I'm having trouble
int i = 0;
//trying to correct the name
//Is this really necessary?
if (isalpha(g->name[0])) {
g->name[0] = toupper(g->name[0]);
}
for (i = 1; i < strlen(g->name); i++) {
g->name[i] = toupper(g->name[i]);
}
//then the surname
//Is this really necessary?
if (isalpha(g->surname[0])) {
g->surname[0] = toupper(g->surname[0]);
}
for (i = 1; i < strlen(g->surname); i++) {
g->surname[i] = toupper(g->surname[i]);
}
g->birth = 2017 - g->birth; //finding how old is the citizen
}
I've also modify you compare function:
int compare(citizen *g1, citizen *g2) {
if (g1->birth == g2->birth) {
int resp = strcmp(g1->surname, g2->surname);
if (!resp) {
return strcmp(g1->name, g2->name);
}
return resp;
} else if (g1->birth > g2->birth) {
return 1;
}
return -1;
}

C Pointers and Access Violation Read Location

I'm new to C and still learning about pointers. I was just testing my understanding of pointers by trying to simulate appending to an array when I got an Access Violation Read Loaction error when using printf. This is the code:
#include <stdio.h>
#include <stdlib.h>
int arraySize(int *arrayToSize);
void changeAll(int ***a1PtrPtrPtr, int nToAdd){
int *bPtr = (int *)malloc((arraySize(**a1PtrPtrPtr) + 1) * sizeof(int));
int i = 0;
while (*(**a1PtrPtrPtr + i) != -1){
bPtr[i] = *(**a1PtrPtrPtr + i);
i++;
}
bPtr[i] = nToAdd; i++;
bPtr[i] = -1;
*a1PtrPtrPtr = &bPtr;
}
int main(void){
int a[4] = { 1, 2, 3, -1 };
int *aPtr = a;
int **aPtrPtr = &aPtr;
int ***aPtrPtrPtr = &aPtrPtr;
int n = 4;
changeAll(aPtrPtrPtr, n);
int counter = 0;
while (counter < 5){
int temp = *(*aPtrPtr + counter);
printf("%d is %d", counter, temp );
counter++;
}
return 0;
}
int arraySize(int *arrayToSize){
int sizeTemp = 0;
int i = 0;
while (arrayToSize[i] != -1){
sizeTemp++;
i++;
}
sizeTemp++;
return sizeTemp;
}
I get the error the second time I print in the while loop in main() when counter = 1. What I don't understand is that if I comment out that printf statement and look at the value of temp value in my IDE (MVSE 2013) it is exactly as I wanted and expected i.e. temp will be 1 then 2,3,4,-1.
What is going on please and thanks in advance for any help.
Firstly, in case you're wondering how this appeared to sometimes work, you really should read this stellar answer to another somewhat related question.
In short, you're saving an address to an automatic variable from inside a function, then treating said-address like it is still valid after the function returns. That the automatic variable is a pointer referring to dynamic data is irrelevant. The variable itself is no longer valid once the function expires, and thus dereferencing its use-to-be-address invokes undefined behavior:
void changeAll(int ***a1PtrPtrPtr, int nToAdd)
{
// NOTE: local variable here
int *bPtr = (int *)malloc((arraySize(**a1PtrPtrPtr) + 1) * sizeof(int));
int i = 0;
while (*(**a1PtrPtrPtr + i) != -1){
bPtr[i] = *(**a1PtrPtrPtr + i);
i++;
}
bPtr[i] = nToAdd; i++;
bPtr[i] = -1;
// NOTE: saving address of local variable here
*a1PtrPtrPtr = &bPtr;
}
With how this is setup, the quickest fix is simply this:
**a1PtrPtrPtr = bPtr;
instead of what you have. This will save the dynamic allocation result to the correct location (which is ultimately the address held in aPtr back in main()). It looks hideous (and frankly, it is), but it will work.
Best of luck.

Resources