Assign an array in a struct in c language - arrays

I have the following code:
#include<stdio.h>
struct student {
int* grades;
int num_grades;
};
double* get_means(struct student* arr, int n); // Function Signature
// grade range is: 0 - 100
// assume max number of grades to one student is up to 100
double* get_means(struct student* arr, int n)
{
arr->grades = 90;
printf("%d", arr->grades);
}
int main()
{
struct student s, *p;
s.grades = malloc(s.num_grades * (sizeof(int)));
p->grades[0] = 1;
printf("%d", p->grades[0]);
}
and I'm having an issue assigning a value (it doesn't matter what the value is, it can be: 0, 7, 50).
The compiler gives me the error:
Error C4700 uninitialized local variable 's' used
Error C4700 uninitialized local variable 'p' used
What can I do to fix this?
In other words: how do I assign a value to an array in a struct?

When you try to do that p->grades[0] = 1 first you need to assign the address for s to p and only than trying to access s from the pointer p. Second issue here is you trying to access array only through is name (in the function get means), As you know array name its only the base address of the array its not the value in it. Third issue its the function does not return nothing but in the prototype it returns pointer to double, I suggest you to change it to avoid any unnecessary warnings or errors.
And another suggestion is including <stdlib.h> when using malloc and always check malloc does not returns you NULL.
The fixed code attached:
struct student {
int* grades;
int num_grades;
};
void get_means(struct student* arr, int n);
void get_means(struct student* arr, int n)
{
arr->grades[0] = 90;
printf("%d", arr->grades[0]);
}
int main()
{
struct student s, *p;
s.grades = malloc(s.num_grades * (sizeof(int)));
/* Option 1
s.grades[0] = 1;
printf("%d", s.grades[0]);
*/
/* Option 2 */
p = &s;
p->grades[0] = 1;
printf("%d", p->grades[0]);
}

Related

two output values through pointer

I had to write the following function, which returns two output values.
In order to do so I used a pointer for the second output value of the quotient. However when I wanted to test it with an input it seemed to be crushing. The code is:
#include <stdio.h>
int div( int n, int m, int *quotient)
{
int d = 0;
while (n >= m) {
n = n - m;
d++;
}
*quotient = d;
return n;
}
int main(void)
{
int *p;
int rest;
rest = div(7, 2, p);
printf("n - %i, d - %i", rest, p);
return 0;
}
would be happy to know how to fix it and why it happened at first place
Thanks for your help
Change this:
int *p;
int rest;
rest = div(7, 2, p);
To this:
int p;
int rest;
rest = div(7, 2, &p);
The problem with your code is that p points some random unallocated place (or is a null pointer if you're lucky). The updated version allocates space for the integer and then passes its address to the function. The function then has a pointer to this address and can write the value there. The memory is allocated on the stack (local variable) and so everything is fine.

C pointer arithmetic palindrome

I'm a java student who's currently learning about pointers and C.
I tried to make a simple palindrome tester in C using a single array and pointer arithmetic.
I got it to work without a loop (example for an array of size 10 :*(test) == *(test+9) was true.
Having trouble with my loop. School me!
#include<stdio.h>
//function declaration
//int palindrome(int *test);
int main()
{
int output;
int numArray[10] = {0,2,3,4,1,1,4,3,2,0};
int *ptr;
ptr = &numArray[0];
output = palindrome(ptr);
printf("%d", output);
}
//function determine if string is a palindrome
int palindrome(int *test) {
int i;
for (i = 0; i <= (sizeof(test) / 2); i++) {
if (*(test + i) == *(test + (sizeof(test) - i)))
return 1;
else
return 0;
}
}
The Name of the array will itself acts as a pointer to an first element of the array, if you loose the pointer then there is no means for you to access the element of the array and hence you can send just the name of the array as a parameter to the function.
In the palindrome function:
you have used sizeof(test)/2. what happens is the address gets divided which is meaningless and hence you should not use that to calculate the mid element.
sizeof the pointer will be the same irrespective of the type of address that gets stored.
Why do you copy your pointer in another variable?
int *ptr;
ptr = &numArray[0];
Just send it to you function:
palindrome(numArray);
And sizeof(test) give you the memory size of a pointer, it's not what you want. You have to give the size in parameter of your function.
int palindrome(int *test, int size){
...
}
Finally your code must look like this:
#include<stdio.h>
int palindrome(int *test, int size);
int main()
{
int output;
int numArray[10] = {0,2,3,4,1,1,4,3,2,0};
output = palindrome(numArray, 10);
printf("%d", output);
}
//function determine if string is a palindrome
int palindrome(int *test, int size) {
int i;
for (i = 0; i < size / 2; i++) {
if (*(test + i) != *(test + (size - 1) - i))
return 0;
}
return 1;
}

Changing variables from outside

In main() function I initialize a couple of variables (int and int* array). Then I print something out and read them from the console scanf.
I want to place this functionality into some external function so that the main will look like this:
int main()
{
int n = 0, x = 0;
int *arr = NULL;
load(&n, &x, &arr);
}
After load() function call I want the variables to be exactly as they were set inside of the load() function. How can I do this?
And second question, just out of curiosity:
/**
* Description of the function
*
* #param int n Foo
* #param int x Bar
* #param int *arr Does something
*/
void load(int n, int x, int *arr)
{
// something
}
Is this documentation useful in C coding, and is it a good practice?
You are passing address of two int and one pointer(third argument), you should receive first two arguments in pointer(one *) to int and third argument in pointer to pointer(two **) of int:
void load(int* n, int* x, int **arr){
// ^ ^ one* ^ two **
*n = 10;
*x = 9;
}
In load function you can assign values to *n and *x because both points to valid memory addresses but you can't do **arr = 10 simply because arr doesn't points to any memory (points to NULL) so first you have to first allocate memory for *arr, do like:
void load(int* n, int* x, int **arr){
*n = 10;
*x = 9;
*arr = malloc(sizeof(int));
**arr = 10;
}
Is this documentation useful in C coding, and is it a good practice?
Yes
but Sometimes I documents my function arguments like in following ways:
void load(int n, // is a Foo
int x, // is a Bar
int **arr){ // do some thing
// something
}
A reference: for document practice
Edit As you are commenting, do like below I am writing, it will not give any error/because of malloc().
#include<stdio.h>
#include<stdlib.h>
void load(int* n, int* x, int **arr){
*n = 10;
*x = 9;
*arr = malloc(sizeof(int));
**arr = 10;
printf("\n Enter Three numbers: ");
scanf("%d%d%d",n,x,*arr);
}
int main(){
int n = 0, x = 0;
int *arr = NULL;
load(&n, &x, &arr);
printf("%d %d %d\n", n, x, *arr);
free(arr);
return EXIT_SUCCESS;
}
Compile and run like:
~$ gcc ss.c -Wall
:~$ ./a.out
Enter Three numbers: 12 13 -3
12 13 -3
As Commented by OP:
"Invalid convertion from void* to int*" when I change this to arr = malloc(sizeof(int)(*n));
syntax of malloc():
void *malloc(size_t size);
malloc() returns void* and *arr type is int* that is the reason compiler messages because of different types : "Invalid convertion from void* to int*"
But I avoid casting when malloc(), since: Do I cast the result of malloc? (read Unwind's answer)

Pointer to 2D struct array C

I have a certain struct structXand a 2D array which holds these kind of structs.
I want to be able to save a pointer to that 2D struct and iterate over it
in a dynamic way, meaning, the pointer can hold any structX and iterate.
Example in general lines:
struct structX *ptr = NULL;
...
if(i == OK)
{
ptr = General_struct_which_holds_others->ptr1;
}
else if(i ==NOT_OK)
{
ptr = General_struct_which_holds_others->ptr2;
}
Now the iteration:
if(ptr[x][y] == OK) <----Error, subscripted value is neither array nor pointer
{
...
}
I hope i'm understood, As i was saying this is very general.
How can the iteration be made? meaning not getting errors?
Thanks!
Two problem I can noticce in your code if(ptr[x][y] == OK)
(1):
ptr is pointer to structure (single *) you can't use double indices [][] so error at if(ptr[x][y] == OK)
error, subscripted value is neither array nor pointer because of ptr[][]
(2):
error: used struct type value where scalar is required means if(struct are not allow).
if(should be a scalar value )
scalar value means can be convert into 0/1.
Pointer to 2D struct array C
struct structX matrix2D[ROW][COL];
its pointer
struct structX (*ptr2D)[ROW][COL];
ptr2D = &matrix2D;
ok, access you array structure like this:
struct structX i;
(*ptr2D)[r][c] = i;
If you want to pass in an function do like:
void to(struct structX* ptr2D[][COL]){
struct structX i;
ptr2D[][COL] = i;
}
void from(){
struct structX matrix2D[ROW][COL];
to(matrix2D);
}
Just to make you sure I written a simple code shows how to work with ptr2D. Hope you find it helpful:
#include<stdio.h>
#define ROW 10
#define COL 5
typedef struct {
int a;
char b;
} structX;
void to(structX ptr2D[][COL], int r, int c){
printf("in to: %d %c\n", ptr2D[r][c].a, ptr2D[r][c].b);
}
int main(){
structX matrix[ROW][COL];
structX (*ptr2D)[ROW][COL];
ptr2D = &matrix;
structX i;
i.a = 5;
i.b = 'a';
int r = 3;
int c = 2;
(*ptr2D)[r][c] = i;
printf("%d %c\n", (*ptr2D)[r][c].a, (*ptr2D)[r][c].b);
to(matrix, r, c);
}
And its working, Output:
5 a
in to: 5 a
EDIT
I wanted to show two tricks but now I think I should provide a uniform method(as you commented):
So here is the code:
#include<stdio.h>
#define ROW 10
#define COL 5
typedef struct {
int a;
char b;
} structX;
void to(structX (*ptr2D)[ROW][COL], int r, int c){
printf("in to: %d %c\n", (*ptr2D)[r][c].a, (*ptr2D)[r][c].b);
}
int main(){
structX matrix[ROW][COL];
structX (*ptr2D)[ROW][COL];
ptr2D = &matrix;
structX i;
i.a = 5;
i.b = 'a';
int r = 3;
int c = 2;
(*ptr2D)[r][c] = i;
printf("%d %c\n", (*ptr2D)[r][c].a, (*ptr2D)[r][c].b);
to(&matrix, r, c);
}
Output
5 a
in to: 5 a
EDIT:
error: used struct type value where scalar is required means if(struct are not allow).
if(should be a scalar value )
you can't do like if((*ptr2D)[r][c]);
but this is allow:
if((*ptr2D)[r][c].a == 5);
or
if((*ptr2D)[r][c].b == 'a');
or
if((*ptr2D)[r][c].a == 5 && (*ptr2D)[r][c].b == 'a');
or
structX i;
if((*ptr2D)[r][c] == i);
You might want to ready this article about multidimensional arrays. If you want to iterate over an array, you need to know how big it is (whether it is dynamic or not). If you want it to be dynamic, that means you need to allocate memory for it when it needs to grow and you need to free the old memory. You also have a problem in your question - you declare a single pointer which is null and then try to dereference it but you never allocated memory for it.
If you did allocate memory for it, you could dereference it by saying
ptr[x * ROW_WIDTH + y]
if you set ROW_WIDTH to the maximum value of y. Depending on whether you want to represent a rows major or column major array, you might use y * width instead of x * width.

C: Accessing a pointer from outside a function

I have the following code:
int takeEven(int *nums, int numelements, int *newlist) {
newlist = malloc(numelements * sizeof *newlist);
int i, found = 0;
for(i = 0; i < numelements; ++i, nums++) {
if (!(*nums % 2)) {
*(newlist++) = *nums;
found++;
}
}
newlist -= found;
printf("First number found %d\n", *newlist); // <= works correctly
return found;
}
int main()
{
int nums[] = {1,2,3,4,5};
int *evenNums;
int i;
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), evenNums);
for (i = 0; i < n; ++i) {
printf("%d\n", *(evenNums++));
}
return 0;
}
The output of the above code:
-1
2088999640
2088857728
If I try printing the first element of the newlist pointer before returning the function (printf("First number found %d\n", *newlist);), it works as intended, but why is it that when I try to access the pointer from outside of the function I get those values from seemingly unmalloced addresses?
You are passing the newList pointer by value, so it will not be modified by your function. You should do instead.
int takeEven(int *nums, int numelements, int **newlist) {
*newlist = malloc(numelements * sizeof *newlist);
...
}
...
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
You need to pass in a pointer to pointer, i.e. int **newlist. Specifically, newlist is being passed into your function by value, so the newlist in main and inside your function are two completely different variables.
There is also a bug in your test for even numbers:
#include <stdio.h>
#include <stdlib.h>
int takeEven(int *nums, int numelements, int **newlist) {
int *list = malloc(numelements * sizeof **newlist);
*newlist = list; // this modifies the value of newlist in main
int i, found = 0;
for(i = 0; i < numelements; ++i, nums++) {
if ((*nums % 2) == 0) {
*(list++) = *nums;
found++;
}
}
list -= found;
printf("First number found %d\n", *list); // <= works correctly
return found;
}
int main()
{
int nums[] = {1,2,3,4,5};
int *evenNums;
int i;
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
for (i = 0; i < n; ++i) {
printf("%d\n", *(evenNums++));
}
return 0;
}
You can also take a look at this question from the C-FAQ which deals with your problem also:
Q: I have a function which accepts, and is supposed to initialize, a pointer:
void f(int *ip)
{
static int dummy = 5;
ip = &dummy;
}
But when I call it like this:
int *ip;
f(ip);
the pointer in the caller remains unchanged.
A: Are you sure the function initialized what you thought it did? Remember that arguments in C are passed by value. In the code above, the called function alters only the passed copy of the pointer. To make it work as you expect, one fix is to pass the address of the pointer (the function ends up accepting a pointer-to-a-pointer; in this case, we're essentially simulating pass by reference):
void f(ipp)
int **ipp;
{
static int dummy = 5;
*ipp = &dummy;
}
...
int *ip;
f(&ip);
Another solution is to have the function return the pointer:
int *f()
{
static int dummy = 5;
return &dummy;
}
...
int *ip = f();
See also questions 4.9 and 4.11.
The newlist you have at the end of the function is not the same as you have when calling the function.
You are passing a copy of a pointer, then malloc changes that pointer(internal to the function) to point to allocated memory, but the outside one is still unmodified.
You need to use a pointer to pointer as a parameter so that you can set where the ourtside one points by double indirection.
int use_pointed_memory(char **pointer){
*pointer = malloc();
}
char *myptr;
use_pointed_memory(&myptr);
So effectively you are giving the function the place where you store the address of what you want and asking the function to store there a valid memory pointer.
You're passing a pointer by value here:
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), evenNums);
Which means that a copy of the pointer is made within that function. You then overwrite that copy:
newlist = malloc(numelements * sizeof *newlist);
Since it is but a copy, the caller won't see the result of your assignment. What you seemingly want here is to pass a pointer by reference - for that, you need a pointer to pointer:
int takeEven(int *nums, int numelements, int **newlist) {
*newlist = malloc(numelements * sizeof **newlist); // apply * to newlist
...
}
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
And don't forget to free:
free(evenNums);
In C, everything is passed by value. So you are passing a copy of evenNums to the function. Whatever you modify it inside the function doesn't get reflected outside. You need to int** as the third parameter.

Resources