I want to create pointers on array in c. For example, I have an array
char arr1[4][20];
I want to make pointers and these pointers would get memory like this pointer p = arr1[0][0-20]
t = arr1[1][0-20], u = arr[1][0-20]. I want to keep all strings from different files in one array.
I try to do something like that, but it's not working.
char name[20][20];
char *s[20];
char *t[20];
s = name[1];
t = name[2];
An array declared like this
char name[20][20];
used in expressions as for example an initializer is implicitly converted to pointer to its firs element that is has the type char ( * )[20].
So you may write for example
char ( *s )[20] = name;
In this case for example to traverse character elements of the array pointed to by the pointer s you need to use expressions like
( *s )[0], ( *s )[1], an so on
Or like
s[0][0], s[0][1], and so on.
It will be simpler to traverse pointed character arrays if pointer would be declared like
char *s = name[0];
char *t = name[1];
and so on.
So either you should declare pointers like
char ( *s )[20] = name;
char ( *t )[20] = name + 1;
or like
char *s = name[0];
char *t = name[1];
Here's how you declare a pointer to an array of 20 elements:
char (*ptr)[20];
So, this is how you do what you want to do:
char name[20][20];
char (*s)[20] = &name[1]; // note the &
char (*t)[20] = &name[2];
And here's how you access elements of those arrays later on:
for (size_t i = 0; i < sizeof(*s); ++i) {
printf("%d ", (*s)[i]);
}
You can round out you question with a short exercise putting the pointer assignments to use. For example continuing from the comment above, with the creation of myptr as a pointer-to-aray of char[20] and s and t to an array of char[20], you could do:
#include <stdio.h>
int main (void) {
const char name[20][20] = { "Mickey Mouse", "Minnie Mouse", "Pluto",
"Bugs Bunny", "Porky Pig", "Daffy Duck", "" },
(*myptr)[20] = name;
while (1) {
const char *s = *myptr++, *t = *myptr++;
if (*s)
puts (s);
else
break;
if (*t)
puts (t);
else
break;
}
}
Example Use/Output
$ ./bin/ptr2arrexercise
Mickey Mouse
Minnie Mouse
Pluto
Bugs Bunny
Porky Pig
Daffy Duck
Question: What purpose does the empty-string serve as the last element of name in the code above?
Related
What is the difference between these two declarations ? How are such variables used in C programs ? Thank you.
char *names[20];
[] takes precedence over *, so the interpretation is: names is an array of size 20. Each array element is of type pointer to char.
char (*place)[10];
In case of using parentheses to override the precedence, the * is applied first: place is a pointer to an array of size 10. Each array element is of type char.
Clockwise/Spiral Rule
char *names[20];
Applying the rule, we learn that names is a 20-element array of pointers to char values.
More clearly, names is an array of 20 char * pointers. This allocates enough memory for 20 such pointers.
sizeof(names) == sizeof(char*) * 20
char (*place)[10];
Applying the rule, we learn that place is a pointer to a 10-element array of char values.
More clearly, place is a pointer, and it points to an array of 10 char. This allocates enough memory for one such pointer.
This declaration
char *names[20];
declares an array with the name names of 20 elements of the type char *. It would be better to write it like
char * names[20];
This declaration
char (*place)[10];
declares a pointer with the name place that points to an array of 10 elements of the type char.
Here is a demonstrative program that I hope makes it more clear.
#include <stdio.h>
int main(void)
{
char * names[20] =
{
"Peter", "Bob", "Mary"
};
for ( char **p = names; *p != NULL; ++p )
{
printf( "%s ", *p );
}
putchar( '\n' );
char city[10] = "Madrid";
char (*place)[10] = &city;
puts( *place );
return 0;
}
The program output is
Peter Bob Mary
Madrid
In this declaration in the above program
char * names[20] =
{
"Peter", "Bob", "Mary"
};
three elements of the array are initialized explicitly by addresses of first characters of the string literals used as initializers. All other 17 elements of the array are implicitly initialized as null pointers.
The same program can be rewritten using typedef(s).
#include <stdio.h>
typedef char * T1;
typedef char T2[10];
int main(void)
{
T1 names[20] =
{
"Peter", "Bob", "Mary"
};
for ( char **p = names; *p != NULL; ++p )
{
printf( "%s ", *p );
}
putchar( '\n' );
T2 city = "Madrid";
T2 *place = &city;
puts( *place );
return 0;
}
The program output will be the same as shown for the previous program.
I would like to reverse a String with an pointer to a function, which executes the String reverse.
I have the feeling that I did not grasp the concept of using pointer to variables or functions correctly, so I would be very thankful if someone could expain me, where I am thinking wrong here:
1) Define a pointer to a function:
char *strrev(char *str)
{
char *p1, *p2;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
2) Now in my main I define a pointer, which matches the function I defined above:
int main(void) {
char (*functPtr)(char);
functPtr = &strrev;
3) Now I define the String, which I want to reverse, define a new pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
4) Lastly I define a new String and write the result of the function, which call through the pointer, which points to the pointer to the function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
return(0);
}
Unfortunaly I get all kinds of error message such as:
Ü1.c:29:10: error: array initializer must be an initializer list or string literal
char t[50] = (*functPtr)(pointer[50]);
^
Ü1.c:27:5: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
pointer[50] = &str[50];
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
Ü1.c:29:30: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
char t[50] = (*functPtr)(pointer[50]);
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
2 warnings and 1 error generated.
1) Define a pointer to a function:
No, you did not define a pointer to function. You defined a function with the name strrev.
2) Now in my main I define a pointer, which matches the function I
defined above:
int main(void) {
char *(*functPtr)(char *);
functPtr = &strrev;
Yes, you defined a pointer to function and initialized it with the address of the function strrev. As function designators used in expressions are implicitly converted to pointers to function then you could write
int main(void) {
char *(*functPtr)(char *);
functPtr = strrev;
3) Now I define the String, which I want to reverse, define a new
pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
Except the definition of the character array that contains a string all other records do not make any sense. For starters the function strrev reverses a string in place. It does not create a reversed copy of the passed to it string.
If you want to declare a pointer that will get the address of the reversed string returned by the function that equal to the address of the original string then you could just write
char *pointer = functPtr( str );
4) Lastly I define a new String and write the result of the function,
which call through the pointer, which points to the pointer to the
function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
You already defined a pointer that will get the value returned from the function. So there is no sense to declare one more array. Moreover arrays do not have the assignment operator. And the function reversed the original string in place. Why are you going to create one more array with the duplicate copy of the original reversed string?! This entirely does not make a sense.
Your program can look the following way
#include <stdio.h>
#include <string.h>
char * strrev( char *s )
{
size_t n = strlen( s );
if ( n )
{
for ( char *first = s, *last = s + n; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main(void)
{
char * ( *fp )( char * ) = strrev;
char s[] = "Hello, World";
puts( s );
puts( fp( s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
If you initially wanted that the function would not reverse the original string but make a reversed copy of the original string then in this case indeed there is a sense to define one additional character array that will get the reversed copy of the original string.
In this case the program can look like.
#include <stdio.h>
#include <string.h>
char *reverse_copy( char *s1, const char *s2 )
{
*( s1 += strlen( s2 ) ) = '\0';
while (*s2)
{
*--s1 = *s2++;
}
return s1;
}
int main(void)
{
char * ( *fp )( char *, const char * ) = reverse_copy;
char s[] = "Hello, World";
char t[sizeof( s )];
puts( s );
puts( fp( t, s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
Now the original character array s was not changed while the array t got the reversed copy of the original string stored in the array s.
I summarize my comments in this answer, as it gives more space for details of the comments.
char (*functPtr)(char); should be char *(*functPtr)(char *); as it takes a pointer to a char, not a char. Likewise it returns a pointer.
char *pointer[50]; would be an array of 50 pointers, You want to say "a pointer to an array of 50 chars". In C we don't say that. We just say "a pointer to a char" and don't say how many. So char *pointer; would be enough.
char t[50] = (*functPtr)(pointer[50]); is not correct in C.
You want to assign the result of funcPtr to the array t. But here you mix initialization with assignment.
char t[50]; declares an array of 50 chars. You can initialize it by giving it a value, for example char t[50] = "Hello World"; which will have the compiler copy "Hello World" to the array.
But you try to assign the function pointer to the array. You probably intend to put the result of the function into the array.
Note also that you cannot "assign" an array to another array. You can only copy it.
So the correct code would be:
char *(*functPtr)(char *);
functPtr = &strrev;
char str[50] = "Hello, World";
char t[50];
char *s= funcPtr(str); // call the function and save the returned pointer
strcpy(t, s); // now copy the result to your array.
printf("%s\n", t); // and print it
Note: char str[50] = "Hello, World"; is correct and, just so you'll know, char *str = "Hello, World"; is wrong. Why? Because the second str will point to read-only memory (a "string literal") and any attempt to modify it would abort the program. But here you did it right.
I have tried searching on the web but found nothing like what I am trying to do. Hope you can help me out.
Problem: I have 2 char arrays, namely string and string2. Both are initially empty. I then give 2 inputs into these strings. I want to assign the value in string using pointers to string2.
Here is my code:
int main(void) {
char string[2][MAXLEN];
char string2[2][MAXLEN];
char *pointer[2];
pointer[0] = &string2[0];
pointer[1] = &string2[1];
scanf("%s", string[0]); //Assume i scan in "ab"
scanf("%s", string[1]); //assume i scan in "cd"
//Now string[0] contains "ab" and string[1] contains "cd"
//I want to deferences the pointer and assign "cd" to it, so string2[0] will contain "cd"
*pointer[0] = string[0];
printf("%s", string2[0]); //but this does not print "cd"
}
*Edit
I understand i can use strcpy, but im trying to learn to do it using pointers. Any help in this regards would be great.
Because you are not copying whole structures of info that the compiler can understand, you need to copy each element of the array individually. Usually this is done with a for loop checking for NUL or size, but I am cheating and just showing you the syntax that would do the copy you want:
#define MAXLEN 10
int main(void)
{
char string[2][MAXLEN];
char string2[2][MAXLEN];
char *pointer[2];
pointer[0] = &string2[0];
pointer[1] = &string2[1];
// Replace scanf for simplicity
string[0][0] = 'a'; string[0][1] = 'b'; string[0][2] = '\0';
string[1][0] = 'c'; string[1][1] = 'b'; string[1][2] = '\0';
// For loop or strcpy/strncpy/etc. are better, but showing array method of copying
pointer[0][0] = string[1][0];
pointer[0][1] = string[1][1];
pointer[0][2] = string[1][2];
printf("%s", string2[0]);
return 0;
}
For pointers, you could do this:
#define MAXLEN 10
int main(void) {
char string[2][MAXLEN];
char string2[2][MAXLEN];
char *pointer[2];
pointer[0] = &string2[0];
pointer[1] = &string[1]; // changed this
string[0][0] = 'a'; string[0][1] = 'b'; string[0][2] = '\0';
string[1][0] = 'c'; string[1][1] = 'd'; string[1][2] = '\0';
*pointer[0]++ = *pointer[1]++;
*pointer[0]++ = *pointer[1]++;
*pointer[0]++ = *pointer[1]++;
printf("%s", string2[0]);
return 0;
}
The pointer magic above turns into:
char temp = *pointer[1]; // Read the char from dest.
pointer[1]++; // Increment the source pointer to the next char.
*pointer[0] = temp; // Store the read char.
pointer[0]++; // Increment the dest pointer to the next location.
and I do it 3 times - one for each char of input. Surrounding that with a while() check against sourcePtr == '\0' basically turns it into strcpy().
One more fun example where a dereference might do what you expect:
typedef struct foo
{
char mystring[16];
} FOO;
FOO a,b;
// This does a copy
a = b;
// This also does a copy
FOO *p1 = &a, *p2=&b;
*p1 = *p2;
// As does this
*p1 = a;
// But this does not and will not compile:
a.mystring = b.mystring;
// Because arrays in 'C' are treated different than other types.
// The above says: Take the address of b.mystring and assign it (illegally because the array's location in memory cannot be changed like this) to a.mystring.
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);
}
I have a bunch of strings that look like:
'Hello1-FOO', 'Aello2-FOO', 'Bye1-BAR', 'Bye3-BAR', 'Hello22-FOO', 'Bye4-BAR', 'Welcome-BAR' ...
All of them are stored on a struct.
struct str {
char *strings;
}
...
struct str **t_str;
size_t j;
t_str = malloc(sizeof *t_str * 20);
for (j = 0; j < 20; j++)
t_str[j] = malloc(sizeof *t_str[j]);
...
t_str[0]->strings = "Hello1-FOO";
t_str[1]->strings = "Aello2-FOO";
....
What I would like to do is to display (sort) them by category, so they look similar to this:
FOO:
Hello1-FOO
Aello2-FOO
Hello22-FOO
BAR:
Bye4-BAR
Welcome-BAR
Bye1-BAR
Bye3-BAR
Basically group them by the token after the '-'
What would be a good way of doing this? Should I store them on a second struct after processing the string? Any idea will be appreciated. Thanks
Just use qsort. The following code makes some assumptions but you should be able to change it to suit your needs.
int categoryComparitor(const void * a, const void * b)
{
char *string1 = (char *)a;
char *string2 = (char *)b;
string1 = strrchr(string1, '-') + 1;
string2 = strrchr(string2, '-') + 1;
return strcmp(string1, string2);
}
{
...
char *strings[]; // Array of string pointers
int stringCount; // Holds current number of valid elements in strings.
...
qsort(strings, stringCount, sizeof(char *), categoryComparitor);
}
As David Thornley already pointed out, your struct isn't really defined well to handle this situation (well at all). Since your input is two separate logical pieces, you really want to define the struct accordingly -- containing two separate strings, one for each part of the input.
struct record {
char *category;
char *string;
};
Then you want to read each piece into one of those two strings:
record read_line(FILE *infile) {
char buffer1[128], buffer2[128];
fscanf(infile, "%[^-]-%s", buffer1, buffer2);
record ret;
ret.string = dupe_string(buffer1);
ret.category = dupe_string(buffer2);
return ret;
}
Then, to sort those records, you'll want to define a comparison function with the signature expected by qsort, that does a comparison on the category member:
int cmp(void *a, void *b) {
return strcmp(((record *)a)->category, ((record *)b)->category);
}
Then you'll sort your array of records using that comparison function.