Access structure variables in a loop - c

My requirement is that i create a structure with variables like
struct stu{
char var_01;
char var_02;
.
.
char var_30;
}stu_t;
and not use an array instead like
char var[30];
With the above requirement established, i can't figure how to access these variables in a loop by concatenating var_ + iterating integer. I know i cant just concatenate, store in a variable and use that variable to access.
Appreciate any help. Thanks!

Variable names have no meaning at run-time in a C program. The names are only for humans, they are removed during compilation. That's why you can't build variable names and somehow use those.
The solution is to use an external array with pointers:
stu_t my_stu;
char * vars[30];
vars[0] = &my_stu.var_01;
vars[1] = &my_stu.var_02;
/* ... and so on ... */
Then you can use vars to access into my_stu:
*vars[0] = 'u';
printf("var_01 is '%c'\n", my_stu.var_01);
Of course this isn't very pretty, but that's what you get.

You can use a pointer for that:
struct stu{
char var_01;
char var_02;
/* ... */
char var_30;
}stu_t;
char* ptr = &stu_t.var_01;
while(ptr <= &stu_t.var_30)
{
*ptr = '0';
printf("Character #%ld = %c \n", ptr - &stu_t.var_01, *ptr);
ptr++;
}

You can use union but it's rather "ugly" hack and I wouldn't recommend it, but if you really want it... (Still, it requires using arrays somewhere! Union will make structure and array use the same location in memory.) Example:
#include <stdio.h>
union Test
{
struct
{
char var_00;
char var_01;
char var_02;
char var_03;
char var_04;
};
char var[5];
};
int main()
{
union Test t;
t.var_01 = 'a';
printf("%c\n", t.var[1]);
return 0;
}
It outputs a.
Anyway, it's better to simply use array. Your requirement is kind of weird...

If your structure only contains chars, you can do this:
typedef struct stu_s {
char a;
char b;
char c;
} stu_t;
int main()
{
stu_t my_struct;
char *ptr = (char *)(&my_struct);
ptr[0] = 1;
ptr[1] = 2;
ptr[2] = 3;
printf("%hhd %hhd %hhd\n", my_struct.a, my_struct.b, my_struct.c);
}

Related

Access structure member char* using offsets

If I have a code:
typedef struct s_ {
int a;
char* b;
} s;
int main()
{
s* st = malloc(sizeof(s));
st->b = malloc(20*sizeof(char));
st->a = 1;
st->b = "foo";
}
Is it possible here to access data in char array using offset?
For example offset here is 4 bytes, I know it and can calculate using for example offsetof() macro, but I can't access data using pointer arithmetics like:
printf("%s", (char*)(st+4));
I would be very happy if someone could help here :)
The answer may be surprising: st+4 actually increments the pointer by 32 bytes!
This is because the type of st is struct s_ * and when you add 4 to that, it is incremented by 4 times the size of the struct.
In order to move by 4 bytes, you need to cast the pointer to char* first and then increment it.
Try this: printf("%s", *(char**)((char*)st + 4));
Edit:
Added *(char**).
It is needed because by incrementing the pointer, we don't get the beginning of the string, we get the address of the pointer to the beginning of the string.
So we need to cast it to the proper type and dereference it.
You can calculate the byte address of the char * element b (which is a char ** value) using (char *)st + offsetof(s, b); therefore you can access the string using code like this:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct s_
{
int a;
char *b;
} s;
int main(void)
{
s *st = malloc(sizeof(s));
st->b = malloc(20 * sizeof(char));
st->a = 1;
strcpy(st->b, "foo");
char *str = *(char **)((char *)st + offsetof(s, b));
printf("[%s]\n", str);
return 0;
}
The output is a line containing [foo].
Now you know why you don't want to have to do this — let the compiler solve it for you:
printf("[%s]\n", st->b);
This question is getting close to Is it possible to dynamically define a struct in C?
If you use printf("%s", (char*)(st+4));,result have been offset 4*struct s
You want to printf the fourth character,could write like this
char *ptr = null;
ptr = st;
printf("[%s]",ptr);

How to initialize struct char array?

I'm having trouble initializing a string of characters belonging to a struct. "Expression must have a modifiable lvalue". Do I need to use strcopy? I am not quite sure how to utilize this. Here is my code:
typedef struct {
char name[50];
int attackDamage;
int magicDamage;
int defense;
int power;
int type;
} ITEM;
int main() {
ITEM item[10];
char itemset[5][5] = { 0 };
char champion1[] = "Gnar";
char champion2[] = "Vi";
char champion3[] = "Fizz";
char champion4[] = "Draven";
char champion5[] = "Braum";
item[0].name = "Brutalizer"; // Having issues here
}
EDIT: I did this and seems there isn't anymore errors. Is this the proper way?
strcpy(item[0].name, "Brutalizer");
item[0].name is an array, you cannot assign a pointer (string literal) to an
array. You need to copy the contents, in this case with strcpy for example:
strcpy(item[0].name, "Brutalizer");
Or if the length of the source is not know beforehand, then you can use
strncpy to avoid buffer overflows:
strncpy(item[0].name, "Brutalizer", sizeof item[0].name);
item[0].name[sizeof(item[0].name) - 1] = '\0'; // make sure that it's \0-terminated
or you can use snprintf
snprintf(item[0].name, sizeof item[0].name, "Brutalizer");

C - how to return more than one char

Anyone know how to return 3 char values from a function to the main part? The three chars have to be input by the user and made into a pyramid. I have been told to use pointers but don't understand how to do it and keep getting errors. These 3 characters then have to be used in the main function to make a pyramid shape.
To expand on my comment, there are basically two ways I would recommend solving this problem, of which the first comes in two variants (depending on use-case and requirements).
Pass an array as argument to the function, and have it filled in. This comes with two variants depending on what is needed:
Just use an ordinary array
void doSomething(char *array)
{
array[0] = 'A';
array[1] = 'B';
array[2] = 'C';
}
Call like
char array[3];
doSomething(array);
printf("First character is '%c'\n", array[0]);
The second variant is basically the same as above, but treats the array as a (null-terminated) string:
void doSomething(char *array)
{
strcpy(array, "ABC");
}
Call like
char array[4]; // One extra for terminator
doSomething(array);
printf("String is '%s'\n", array);
The second way to return multiple values is through the use of structures:
struct Data
{
char a;
char b;
char c;
};
struct Data doSomething(void)
{
struct Data data;
data.a = 'A';
data.b = 'B';
data.c = 'C';
// or struct Data data = { 'A', 'B', 'C' };
return data;
}
Call like
struct Data data = doSomething();
printf("First character is '%c'\n", data.a);
I write an example of pointers, I hope it's useful:
main(){
int a,b,c;
doSomething(&a,&b,&c);
}
void doSomething(int *x, int *y, int *z){
//example
*x = 5;
*y = 7;
*z = 10;
}

Array/Pointer: Left operand must be l-value

I've just started out with C and I'm struggling to get to grips when mixing pointers and arrays.
I am getting the following error:
error C2106: '=' : left operand must be l-value
#include <stdio.h>
struct PersonDetails {
char *name;
int *phoneNumber;
};
int* getPhoneNumber(struct PersonDetails *phoneBook[], char* name);
int main() {
struct PersonDetails a;
struct PersonDetails b;
struct PersonDetails people[2];
struct PersonDetails *ptr[2];
char aName = 'T';
int aNum = 123;
char bName = 'O';
int bNum = 456;
a.name = &aName;
a.phoneNumber = &aNum;
b.name = &bName;
b.phoneNumber = &bNum;
people[0] = a;
people[1] = b;
ptr = &people;
printf("%d", *getPhoneNumber(ptr, aName));
return 0;
}
int* getPhoneNumber(struct PersonDetails *phoneBook[], char* name) {
int i;
for (i = 0; i < 2; i++) {
if (*phoneBook[i]->name == *name) return phoneBook[i]->phoneNumber;
}
return 0;
}
It's happening on the line:
ptr = &people;
Edited Code:
#include <stdio.h>
struct PersonDetails {
char *name;
int *phoneNumber;
};
int* getPhoneNumber(struct PersonDetails *phoneBook[], char* name);
int main() {
struct PersonDetails a;
struct PersonDetails b;
struct PersonDetails people[2];
struct PersonDetails *ptr;
char aName = 'T';
int aNum = 123;
char bName = 'O';
int bNum = 456;
a.name = &aName;
a.phoneNumber = &aNum;
b.name = &bName;
b.phoneNumber = &bNum;
people[0] = a;
people[1] = b;
ptr = people;
printf("%d", *getPhoneNumber(ptr, aName));
return 0;
}
int* getPhoneNumber(struct PersonDetails *phoneBook, char* name) {
int i;
for (i = 0; i < 2; i++) {
if (*phoneBook[i].name == *name) return phoneBook[i].phoneNumber;
}
return 0;
}
Transferring sundry comments of mine in dialogue with the OP into an answer
Because the method getPhoneNumber() requires the parameter struct PersonDetails *phoneBook[].
Why does getPhoneNumber() require that eccentric type? There must be a reason why you chose to use it (like "the teacher set that in the question I'm working on"). Otherwise, it seems more likely that the parameter should be either struct PersonDetail *who or struct PersonDetail who[] — which, in the context of a function's parameter list (and only in the context of a function's parameter list) amounts to the same thing.
Originally it was PersonDetails *phoneBook, but I didn't think that would work? Am I wrong in thinking that, and how would I go about using that to find a number using a name?
Assuming you mean struct PersonDetails *phoneBook (there isn't a type PersonDetails in your code, but there is the type struct PersonDetails), then that would work fine. It is a pointer parameter that can either point to a single person's details, or to the start of an array of people's details. Inside the function, as long as you know that the array is big enough, you can use phoneBook[i].name or phoneBook[i].number with care. (Or, indeed, phoneBook->name and phoneBook->number, which refer to the single element pointed at by phoneBook, or you can think of it as using an effective subscript of 0.)
Oh wow, thank you, that helps so much. So I would change ptr to just struct PersonDetails *ptr; as opposed to an array of pointers?
Yes — using struct PersonDetails *ptr; is all you need. You are (accidentally) delving into more complex structures which do have a place in more complex situations, which is why no-one could say "this is wrong", but they're currently beyond what you need, or what you currently understand. That's OK; what you've just learned probably covers 95% or more of real life use cases.
Okay, it all compiles now, but crashes when executed. I have a feeling it has something to do with how I'm assigning both ptr and people. Do I just delete the people array? I've added an edited section in the question if you could have a look for me please?
You are now passing a char value, aName, where the function expects a char *, which would be &aName. The function prototype at the top also doesn't match the function definition; the definition is correct. You need to remove either the * or the [] but not both from the prototype. With that, it 'works'.
Be aware that you don't have strings (the char * values do not point to null terminated arrays of characters) so you can't do string comparison (strcmp()), but fixing that is probably the next phase of development.
Your compiler should have been generating warnings; pay heed. Remember, it knows a lot more about C than you do at the moment!
Working code
#include <stdio.h>
struct PersonDetails
{
char *name;
int *phoneNumber;
};
int *getPhoneNumber(struct PersonDetails *phoneBook, char *name);
int main(void)
{
struct PersonDetails a;
struct PersonDetails b;
struct PersonDetails people[2];
struct PersonDetails *ptr;
char aName = 'T';
int aNum = 123;
char bName = 'O';
int bNum = 456;
a.name = &aName;
a.phoneNumber = &aNum;
b.name = &bName;
b.phoneNumber = &bNum;
people[0] = a;
people[1] = b;
ptr = people;
printf("%d\n", *getPhoneNumber(ptr, &aName));
return 0;
}
int *getPhoneNumber(struct PersonDetails *phoneBook, char *name)
{
int i;
for (i = 0; i < 2; i++)
{
if (*phoneBook[i].name == *name)
return phoneBook[i].phoneNumber;
}
return 0;
}
Note that printing the result directly as shown will fail horribly (usually) if the 'name' is not found. You'll be dereferencing a null pointer, which invokes undefined behaviour — A Bad Thing™! You really need to use:
int *p_number = getPhoneNumber(ptr, &name);
if (p_number == NULL)
printf("No entry for name %c\n", name);
else
printf("Number for %c is %d\n", name, *p_number);
You should also review why you have int *number; instead of just int number; or char *number;. The former is better if you simply store an unformatted integer; the latter is better if you might need to store +44 1395 276679 or something like that, though you should then consider the relative merits of char number[MAX_PHONE_NUMBER_STRING_LEN]; instead of a pointer.
Also, for more nearly general-purpose code, your function should probably be told how many entries there are in the phone-book, rather than using a hard-wired size of 2 (which is a pretty minimal phone-book by any standard):
int *getPhoneNumber(int n_entries, struct PersonDetails *phoneBook, char *name)
{
int i;
for (i = 0; i < n_entries; i++)
{
if (*phoneBook[i].name == *name)
return phoneBook[i].phoneNumber;
}
return 0;
}
Where the number of entries in the array is a parameter. Assuming you have C99 or C11, you could also sensibly write that as:
int *getPhoneNumber(int n_entries, struct PersonDetails phoneBook[n_entries], char *name)
{
for (int i = 0; i < n_entries; i++)
{
if (*phoneBook[i].name == *name)
return phoneBook[i].phoneNumber;
}
return 0;
}
In both these last samples, I've not changed the data types in the structure (even though I think they should be changed). I've also not added const qualifiers to the pointer/array or the name, even though both could legitimately be const-qualified.
struct PersonDetails *ptr[2];
ptr is an array of pointers and array itself is never a modifiable value. lvalue should be some location where you store values(like variable). So this is an error.
You define as follows -
struct PersonDetails people[2];
struct PersonDetails *ptr[2];
which means the people is a 2-element array of structs of type PersonDetails, while ptr is a 2-element array of pointers to such structs.
You can't override the address of an array, it's not just some pointer (although there are some mutual semantics), it's allocated on the stack.
If you meant each element in ptr to point to the respective people element, use a loop:
for (i = 0; i < 2; ++i)
ptr[i] = &people[i];
Also note that one of the effects of passing around all these pointers to simple variables defined in main, is that you can return a null pointer from getPhoneNumber, and pass it to printf - that would segfault
ptr is an array of pointers to struct PersonDetails, so ptr[0] and ptr[1]
are pointers to struct PersonDetails, then you can asign the address of a variable of the type struct PersonDetails to each element of ptr.
in C an array is something like a pointer (but it's not exactly the same) which points to a part of the
memory (with the size of the type of variables times the numbers of elements of the array) where you can store one or more variables of one type, so in
your example, you could see people like a pointer to struct PersonDetails, and ptr like a pointer to a pointer to struct PersonDetails.
So, with all that said, what you can do is ptr[0] = people or ptr[1] = people.

Swap char with table pointers in C

I'm trying to swap two char with two table pointers.
Can someone explain to me what's wrong in my code?
The terminal says char** is expected but I don't know what to do, so I think I don't really understand how pointers work for tables.
void echangeM2(char **ptab1, char **ptab2){
char *tmp = *ptab1;
*ptab1 = *ptab2;
*ptab2 = *tmp;
printf("%s\t %s",*ptab1,*ptab2);
return;
}
int main(void) {
char tab1[25];
char tab2[25];
char *adtab1;
char *adtab2;
*adtab1 = &tab1;
*adtab2=&tab2;
printf("type two words");
scanf("%s %s",tab1,tab2);
echangeM2(adtab1,adtab2);
return 0;
}
The following code should work for you:
#include <stdio.h>
void exchangeM2(char* *ptab1, char* *ptab2) { // accepts pointer to char*
char* tmp = *ptab1; // ptab1's "pointed to" is assigned to tmp
*ptab1 = *ptab2; // move ptab2's "pointed to" to ptab1
*ptab2 = tmp; // now move tmp to ptab2
printf("%s\t %s",*ptab1,*ptab2);
}
int main(void) {
char tab1[25];
char tab2[25];
char* adtab1;
char* adtab2;
adtab1 = tab1; // array name itself can be used as pointer
adtab2 = tab2;
printf("type two words");
scanf("%s %s",tab1,tab2);
exchangeM2(&adtab1, &adtab2); // pass the address of the pointers to the function
}
echangeM2(&adtab1,&adtab2);
This should fix the compile errors. You are passing char* pointers to a function that expects a char ** pointer
Edit: Actually looks like you want something like
char **adtab1;
char **adtab2;
adtab1 = &tab1;
adtab2=&tab2;
...
echangeM2(adtab1,adtab2);

Resources