How to increment index and print the right string with pointer? - c

The code uses a struct ( int x,y) to print message when c->x increase the value by 1,
but unlike c->x , ptr1 pointer "forgets" its address.
How can I create a pointer to string array without "forgetting" its address?
#include <stdio.h>
#define msgROW 5
#define msgLEN 16
struct cursxy{
unsigned int x;
unsigned int y;
};
void cursor(struct cursxy *c,char (*ptr1)[msgLEN])
{
c->x++;
printf("%s \n", *ptr1++);
}
int main()
{
struct cursxy cursxy = {0,0};
char messages[msgROW][msgLEN] =
{
"Set Duty Cycle",
"Set Frequency",
"Set Hours",
"Set Minutes",
"Set Current"
};
char (*ptrMsg)[msgLEN] = messages;
//c->x = 1 , prints first message
cursor(&cursxy,ptrMsg); //ptrMsg point to first message
//c->x = 2 , prints again the first message
cursor(&cursxy,ptrMsg); //ptrMsg Didn't point to second message <------------
// and so on
}

The difference between the expressions
c->x++
and
*ptr1++
is that the latter modifies a function argument, whereas the former does not.
In C, functions have their own copy of the values of the function arguments that were used to call the function. As a consequence, modifying these arguments inside the function will not modify the original variable.
Therefore, in the function cursor, any changes to the function argument ptr1 will not change the variable ptrMsg in the function main.
The simplest solution to your problem would be to increment ptrMsg inside the function main instead of inside cursor.
However, if you insist on changing ptrMsg from inside cursor, then you will have to pass the variable ptrMsg by reference instead of by value. This means that you will have to instead pass the address of ptrMsg to the function cursor, like this:
cursor(&cursxy,&ptrMsg);
You will also have to change the prototype of the function cursor, so that the second parameter has an additional layer of indirection. Additionally, you will have to add a * dereference operator in order to access the original variable via the pointer. Afterwards, your function will look like this:
void cursor(struct cursxy *c,char (**ptr1)[msgLEN])
{
c->x++;
printf("%s \n", *( (*ptr1)++ ) );
}

this is what you're looking for.
same as cursxy, use double pointer.
#include <stdio.h>
#define msgROW 5
#define msgLEN 16
struct cursxy{
unsigned int x;
unsigned int y;
};
void cursor(struct cursxy *c, char (**ptr1)[msgLEN])
{
c->x++;
printf("%s \n", *ptr1);
*ptr1 = ++*ptr1;
}
int main()
{
struct cursxy cursxy = {0,0};
char messages[msgROW][msgLEN] =
{
"Set Duty Cycle",
"Set Frequency",
"Set Hours",
"Set Minutes",
"Set Current"
};
char (*ptrMsg)[msgLEN] = messages;
char (**ptr)[msgLEN] = &ptrMsg;
//c->x = 1 , prints first message
cursor(&cursxy, ptr); //ptrMsg point to first message
//c->x = 2 , prints second message
cursor(&cursxy, ptr); //ptrMsg Didn't point to second message <------------
cursor(&cursxy, ptr); //ptrMsg Didn't point to second message <------------
// and so on
}

Related

Unclear behavior of structs in a function

I am creating a project and I encountered behavior that is not supposed to happen (at least as far as I know). I am trying to change values in a struct array inside of a function addOrder. in main() I give struct's address to a function addOrder (and this is the first warning). Then I try to change its contents in the named function. I should only be able to change using ->, however, I get errors this way and I can only change using data[0].someName
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define MENU_TITLE "----Welcome to order manager!---" // menu title
#define MENU_SIZE 4 //change based on menu options
#define INPUT_MSG "Please choose one of the following options" //enter input message (range is added later automatically)
#define SIZE 25 //size of option message array
#define STREET_NAME_SIZE 50 //size of street name array
#define BUILDING_NUMBER_SIZE 10 //size of building number array
#define EMAIL_SIZE 40 //size of email array
#define INPUT_PHONE_MAX 12
typedef struct Data{
char streetName[STREET_NAME_SIZE];
char buildingNumber[BUILDING_NUMBER_SIZE];
unsigned long long phoneNumber;
char email[EMAIL_SIZE];
}Data;
void loadOrderAmount(int *orderAmount);
void showMenu(char *menuTitle, int menuSize, char *inputMsg);
int getChoise();
void addOrder(Data *data, int *orderAmount);
void getEmail(char *email);
unsigned long long getPhoneNumber();
int main(){
int orderAmount = 0;
loadOrderAmount(&orderAmount);
Data data[orderAmount + 1];
int choise = 0;
showMenu(MENU_TITLE, MENU_SIZE, INPUT_MSG);
while(!choise){
choise = getChoise();
}
printf("\n");
switch(choise){
case 1:
addOrder(&data,&orderAmount); // This gives first warning
break;
case 2:
//removeOrder(data);
break;
case 3:
//editOrder(data);
break;
case 4:
printf("Have a nice day\n");
return 0;
}
printf("in main data %d\n",&data);
//printf("%s %s ",data[0].streetName,data[0].buildingNumber);
//printf("+%llu ",data[0].phoneNumber);
printf("in main %s %llu\n",data[0].email,data[0].phoneNumber);
return 0;
}
void addOrder(Data *data,int *orderAmount){
int amount = *orderAmount; //it is equal to 0
char email[41];
char street[51];
char buildingNumber[11];
printf("Adding an order...\n\n");
//++orderAmount;
// getStreetName(data, &orderAmount);
// getBuildingNumber(data,&orderAmount);
data[amount]->phoneNumber = getPhoneNumber(); //why this does not work?
getEmail(email);
strcpy(data[0].email,email); // why this works? its a function....
printf("In function data %d\n", data);
printf("in struct %s %llu\n",data[0].email, data[0].phoneNumber);
}
}
This is only a part of a code that is relevant and most functions are missing. Can anyone help me with this?
The function addOrder is declared like
void addOrder(Data *data, int *orderAmount);
But you are calling it passing the first argument of the type Data ( * )[orderAmount + 1]
addOrder(&data,&orderAmount);
You need to call it like
addOrder( data, &orderAmount );
Instead of this statement
data[amount]->phoneNumber = getPhoneNumber();
you have to write
data[amount].phoneNumber = getPhoneNumber();
And instead of this call
printf("In function data %d\n", data);
you have to write
printf("In function data %p\n", ( void * )data);
Pay attention to that within the function the expressions
data[amount]
and
data[0]
are not the same because amount is not equal to zero. The function is called with the argument orderAmount (passed by reference) that is assigned to amount.
This is how you solve this error:
Compiler points at the line addOrder(&data,&orderAmount); saying something strange "error passing argument 1 blablabla". We don't actually need to understand more than "error argument 1".
Could it be that the compiler is right and something is wrong with argument 1?
Hmm which one is argument 1, it must be &data.
Check the declaration of data, it is Data data[orderAmount + 1];. It's an array!
What did they teach us in beginner class? Ah, arrays decay to a pointer to the first element when passed to a function. So there is no need for &.
Change the call to addOrder(data,&orderAmount);
Compile again.

How to return type char from function pointer in c [duplicate]

This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 5 years ago.
Wrote the following code that takes the time input from a struct and prints it all together into a string:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct time
{
int hour;
int minute;
char am_pm [3];
char (*standard_time)(struct time *self);
};
char standard_time_format(struct time *self)
{
char standard_format[8], conversion[3];
int length;
length = snprintf(NULL, 0, "%d", self->hour);
snprintf(conversion, length + 1, "%d", self->hour);
strcpy(standard_format, conversion);
strcat(standard_format, ":");
length = snprintf(NULL, 0, "%d", self->minute);
snprintf(conversion, length + 1, "%d", self->minute);
strcat(standard_format, conversion);
strcat(standard_format, self->am_pm);
return(standard_format);
}
int main()
{
struct time start;
char standard_format[8];
start.hour = 2;
start.minute = 34;
strcpy(start.am_pm, "am");
start.standard_time = standard_time_format;
strcpy(standard_format, start.standard_time(&start));
printf("%s\n", standard_format);
return 0;
}
However, it is unable to print out the result as the return type doesn't seem to be compatible.
Changing types to pointers didn't fix it either:
in the struct:
char *(*standard_time)(struct time *self);
the function:
char *standard_time_format(struct time *self)
and in both routines creating a pointer to standard_format:
char *str = &standard_format;
and returning the pointer in the function:
return(str);
So what type exactly is being returned, and how can it be accessed properly to display it in the printf command?
EDIT
As suggested in the answers, I modified the code such that a string was passed as an argument to the function instead, which remedied the issue. The following is the updated code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct time
{
int hour;
int minute;
char am_pm [3];
void (*standard_time)(struct time *self, char standard_format[8]);
};
void standard_time_format(struct time *self, char standard_format[8])
{
char conversion[3];
snprintf(conversion, sizeof(conversion), "%d", self->hour);
strcpy(standard_format, conversion);
strcat(standard_format, ":");
snprintf(conversion, sizeof(conversion), "%d", self->minute);
strcat(standard_format, conversion);
strcat(standard_format, self->am_pm);
}
int main()
{
struct time start;
char standard_format[8];
start.hour = 2;
start.minute = 34;
strcpy(start.am_pm, "am");
start.standard_time = standard_time_format;
start.standard_time(&start, standard_format);
printf("%s\n", standard_format);
return 0;
}
In the standard_time_format function when you do
return(standard_format);
you attempt to return a pointer to the first element in the array standard_format (remember that arrays decays to pointers to its first element, i.e. &standard_format[0]). Its type is char *.
However this is very problematic since standard_format is a local variable inside the function, and it will go out of scope once the return statement have been executed, leaving you with a dangling pointer which you can't dereference (attempting to do so will lead to undefined behavior).
The simple and standard solution is to pass the string to be filled as an argument to the function.
return(standard_format);
Here you have returned pointer that points to local variable when standard_time_format returns its stack will be deallocated and eventually standard_format that you returned will become invalid
You should pass char array to standard_time_format and copy the string that you want to return in it, instead of returning local variable

Modify argument without return

I have a problem in C. I have this function :
int test(void *data);
I want to change data with this function but I don't want another prototype (not use void **). Actualy, data equals null out this function.
#include <stdio.h>
#include <stdlib.h>
int
test(void *data)
{
data = "toto";
return 1;
}
int
main()
{
void *d;
if (test(d) != 1) {
printf("erreur\n");
}
printf("résultat : %s\n", (char *) d); // displays "résultat : (null)"
return 0;
}
Help me please. ;)
In C arguments to function are passed by value. d is passed by value to function test. data is a local variable to function test and d is copied to data. The assignment
data = "toto";
makes pointer data to point to string literal toto, while d is unaffected of this assignment in main function. So, this assignment has no effect on d.
In main you are dereferencing an uninitialized pointer. This will result in undefined behavior.
In your test function, you change data, which doesn't affect d because data is just a local variable. If you really need to change d, then you need to let test return data and do d=test(d).
Moreover, in your test function, the value of data is never used. So what is the point to have data as a parameter of the function?
In printf("résultat : %s\n", (char *) d);, you try to cast d into pointer to char and then print the value of d. Although you don't dereference d, you are still printing a variable that hasn't been initialized, which is undefined behavior.
Any object pointer (i.e. non-function pointer) can be converted to a void * and back to the original type without altering the value. This means that you can pass any kind of (object) pointer to your test() function, it will be automatically converted to a void *, and you can then convert it back inside test().
#include <stdio.h>
int test(void *data)
{
char **s = data;
*s = "toto";
return 1;
}
int main()
{
char *res;
if (test(&res) != 1) {
printf("erreur\n");
}
printf("résultat : %s\n", res);
return 0;
}
You just need to make sure that the test() function knows what the original type was.

How do I handle a struct component which points to an array whose size won't be known until after the struct is declared?

I have a struct with a pointer component. The pointer will point to an array whose size will be determined after the struct is declared. I will need to malloc memory and then assign it to the pointer. Somehow passing this pointer through function calls causes problems. Here is a simple example which recreates my error:
#include <stdlib.h>
#include <stdio.h>
typedef struct mystruct mystruct;
struct mystruct{
int dim;
double *dubarr;
double dub;
};
int getarr(int *dim, double *dubarr){
*dim = 2; /* The value of dim is not known until this function is called */
dubarr = malloc(*dim * sizeof(double));
double test;
int i;
for(i=0;i<*dim;i++)
{
dubarr[i] = (i+1)*7.0;
test = dubarr[i];
printf("dubarr[%i] = %.15e\n", i, test);
}
return 1;}
int initmystruct(mystruct *data){
getarr(&(data->dim),data->dubarr);
data->dub = (data->dim)*((data->dubarr)[0]);
return 1;}
int main(void){
mystruct data;
initmystruct(&data);
double test;
int i;
for(i=0;i<data.dim;i++)
{
test = (data.dubarr)[i];
printf("dubarr[%i] = %.15e\n", i, test);
}
/* I would do "free(data.dubarr);" here but it causes a crash */
return 1;}
The code compiles with no warnings but the components of data.dubarr do not maintain their values through the function calls. Here is the output:
dubarr[0] = 7.000000000000000e+00
dubarr[1] = 1.400000000000000e+01
dubarr[0] = 2.002400628035951e+176
dubarr[1] = 2.186218092030684e-154
Please point out all my mistakes :)
C uses pass by value. So here:
int getarr(int *dim, double *dubarr)
the function receives dubarr, a pointer to double, passed by value. So, whatever the function assigns to dubarr cannot be seen outside getarr. Note that the implementation of getarr modifies dubarr, but the caller will not see those modifications.
Contrast that with how you handle dim, where you modify *dim. Similarly look at the call to getarr in your code:
getarr(&(data->dim), data->dubarr);
Observe how the two arguments are treated differently. For the first argument you pass the address of a variable, for the second you pass the value of the pointer.
Instead you need:
int getarr(int *dim, double **dubarr)
And then assign to *dubarr like this:
*dubarr = malloc(...);
And call getarr like this:
getarr(&(data->dim), &(data->dubarr));

const char passed to a function is not reflecting back

I want to change the contents of a constant-character-array(const array[64]).
Below is my code.
My Question is, why does the constant character array doesn't change(not reflected back), when passed to the function as constant character pointer(const char *append)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int function(char *d,const char *append)
{
append = d; //changing the location of append.
printf ("%s\n",append); //displays as sachintendulkar.
}
int main()
{
char *d = NULL;
const char append[]={'s','a','c','h','i','n'};
d = calloc(sizeof(char),sizeof(append));
strcpy(d,append);
strcat(d,"tendulkar"); //appending
function(d,append);
printf ("%s\n",append); //Its displays as sachin instead of sachintendulkar???
}
Function arguments are passed by value, when you assign a new value to the pointer append inside function(), nothing happens that is noted outside the function.
It's not very clear what you're trying to do ... The point of constant data is, of course, that you're not supposed to change it.
It is just a coincidence that the names of the parameters are the same as the variables in main. There is no connection between the names.
Your function works the same as if it was
int function(char *x, const char *y)
{
 y = x; //changing the location of y.
 printf ("%s\n", y); //displays as sachintendulkar.
}
You wouldn't expect that function to change the values inside main.

Resources