I'm converting Java code to C, and something as simple as swapping contents of multi arrays in Java:
boolean[][] temp = board;
board = nextBoard;
nextBoard = temp;
Seems to be a lot more troublesome in C.
After viewing similar questions on this site, I have learned that I have to use memcpy which I initiated in a method called arrayCopy.
This is arrayCopy:
void arrayCopy(char * a, char * b)
{
struct universe data;
int r;
for(r = 0; r < data.rows; r++)
memcpy(b, a, sizeof(a));
}
Which I call from the main method:
char temp[SIZE][SIZE];
arrayCopy(&data.board, &temp);
arrayCopy(&data.nextBoard, &data.board);
arrayCopy(&temp, &data.nextBoard);
With the following struct:
struct universe
{
char board[SIZE][SIZE];
char nextBoard[SIZE][SIZE];
int columns;
int rows;
}universe;
But I'm getting warnings such as:
A2Q1.c:189:15: warning: incompatible pointer types passing
'char (*)[60][60]' to parameter of type 'char *'
Yet memcpy only returns pointers, so I can't switch the parameters. I also can't use malloc() yet as other questions suggest because I have not learned it yet, so any other suggestions would be appreciated.
try this
void swapBoard(struct universe *x){
char temp[SIZE][SIZE];
memcpy(temp, x->board, sizeof(temp));
memcpy(x->board, x->nextBoard, sizeof(temp));
memcpy(x->nextBoard, temp, sizeof(temp));
}
int main(){
struct universe data;
//...
swapBoard(&data);
I think you are making it a bit over-complicated. You can use memcpy directly in your example above to copy everything from a to b without iterating through it. If you run this code...
int main()
{
char temp[60][60];
printf("%d", sizeof(temp));
}
You'll see that sizeof will give you 3600 bytes, 60*60 to the total bytes allocated by the array. These byte are allocated in a contiguous chunk of memory and memcpy can copy them in one swoop. This demonstrates the point:
int main()
{
char temp[60][60];
memset(temp, 'a', sizeof(temp));
char temp2[60][60];
memset(temp2, 'b', sizeof(temp2));
memcpy(temp2, temp, sizeof(temp2));
printf("%c", temp2[23][34]);
}
The printf will print 'a'. In your code above, this should work just fine:
char temp[SIZE][SIZE];
memcpy(data.board, temp, sizeof(data.board));
memcpy(data.nextBoard, data.board, sizeof(data.nextBoard));
memcpy(temp, data.nextBoard, sizeof(temp));
Note that this assumes all of these arrays are identical in size. You may want to create a minsize function or use a macro function like #define MINSIZE(a,b) (sizeof((a)) < sizeof((b)) ? sizeof((a)) : sizeof((b))) to be safe.
Related
I am using Mac OS to implement part of function of command sort:
part of my code is below:
int compare(const void *p, const void *q) {
return strcmp(*(char **)p, *(char **)q);
}
void sort_file(char *filename, int unique, int reverse) {
/* TODO: Complete this function */
/* Note: you will probably need to implement some other functions */
char buf[1024][1024];
int i=0;
FILE * fp;
if(!(fp=fopen(filename,"r"))){
perror("Open error!");
exit(0);
}
while(fgets(buf[i],1024,fp)){
printf("%s",buf[i]);
i++;
}
qsort(buf, i, sizeof(char *), compare);
}
The result always show segmentation fault: 11
Anyone can tell me what's the problem and how to modify it?
I still want to know, if I don't know the maximum size of code in one line and in the file, how to define my array?
I get the idea from this page:
http://www.anyexample.com/programming/c/qsort__sorting_array_of_strings__integers_and_structs.xml
You don't have an array of pointers; you have an array of arrays. Each element in your array of arrays has a specific, fixed stride of 1024 char. qsort needs to know that, and you're not telling it. First change this:
qsort(buf, i, sizeof(char *), compare);
to this:
qsort(buf, i, sizeof *buf, compare);
Now qsort knows how big each "thing" is in your array of char arrays.
Next, your comparator should be altered to account for the address being passed and what it is as it pertains to your array of arrays. Each address passed to the comparator is where an element lays. But your elements are each char[1024]. The address of some char[1024] isn't some char**, it is char(*)[1024]. There are no pointers to pointers involved here. Your comparator can simply be:
int compare(const void *p, const void *q)
{
const char (*lhs)[1024] = p;
const char (*rhs)[1024] = q;
return strcmp(*lhs, *rhs);
}
Next, there is no limiter in you control loop to prevent overflowing your array of arrays. In short, this:
while(fgets(buf[i],1024,fp))
should be this:
while(i < 1024 && fgets(buf[i],1024,fp))
and ideally, that 1024 should be expressed as a constant somewhere to avoid magic number sprinkling.
Finally, you're leaking an open FILE* in your function. Not a good plan. Make sure to fclose() your file pointer.
Problems I see:
Wrong argument to qsort
qsort(buf, i, sizeof(char *), compare);
Needs to be:
qsort(buf, i, sizeof(buf[0]), compare);
Since the difference between buf+1 and buf is 1000 chars, it is wrong to use sizeof(char*) as the third argument.
Wrong casting of the arguments in compare
The original pointers are of type char (*)[1000], not char**. Hence you need to use:
int compare(const void *p, const void *q) {
char (*p1)[1000] = (char (*)[1000])(p);
char (*q1)[1000] = (char (*)[1000])(q);
return strcmp(*p1, *q1);
}
#include <stdio.h>
void swap(void *v[], int i, int j)
{
void *tmp;
tmp = v[i];
v[i] = v[j];
v[j] = tmp;
}
int main(void)
{
char *s[] = {"one", "two"};
printf("%s, %s\n", s[0], s[1]);
swap(s, 0, 1);
printf("%s, %s\n", s[0], s[1]);
return 0;
}
Output:
one, two
two, one
Warning: no compatible pointer casting, need void**, but char
I used this program to simulate the swap function in K&R, to demonstrate the use of the function pointer, and my question is whether the cast of the void pointer is always safe, or if there is any way to replace it.
No, it is not necessarily safe to pass a char** where a void** (which is what a void*[] function parameter actually is) is expected. The fact that the compiler makes you perform an explicit cast is a hint about that.
In practice, it is likely to be fine. Strictly speaking, however, you usually have no guarantee that sizeof (T*) == sizeof (U*) for distinct types T and U. (For example, you could imagine a hypothetical system where sizeof (int*) < sizeof (char*) because pointers-to-int are aligned and therefore don't need to store the least significant bits.) Consequently, your swap function might index into the v array using the wrong offsets.
Also see Q4.9 from the comp.lang.c FAQ: Can I give the formal parameter type void **, and do something like this?
To call swap safely, you should do something like:
void* temp[] = { &s[0], &s[1] };
swap(temp, 0, 1);
although that would swap the elements of temp, not of s.
If you're authoring swap, in general you should make such a function take a void* argument (instead of a void** one) and a size_t argument that specifies the size of each element. Your function then could cast the void* to char* safely and swap individual bytes:
void swap(void* p, size_t elementSize, size_t i, size_t j)
{
char* item1 = p;
char* item2 = p;
item1 += i * elementSize;
item2 += j * elementSize;
while (elementSize-- > 0) {
char temp = *item1;
*item1 = *item2;
*item2 = temp;
item1++;
item2++;
}
}
Edit:
Also see this StackOverflow answer to a similar question.
You need to typecast the pointer in swap call. Change it to swap ( ( void * )s, 0, 1 );
To avoid the warning call the function as follows,
swap((void *) s, 0, 1);
It is always safe to cast any pointer as a void pointer.
I have seen some of the other answers on this topic but dont really understand them enough to fit them to my problem. I have a 2D array of pointers to char that I want to pass to a function.
If the array is declared: char *params[50][50]; (50 is just picked arbitrarily)
and the function prototype is: void test (char ***results);
How would I call the function? everything I try ends up with an incompatible pointer warning
Also what is the most correct way to then refer to the members of the array while inside the function? is it simply: results[x][y]; ?
Thanks
you can't, pointers to pointers and pointers to arrays are different things.
void test (char *results[50][50]);
void test (char *results[][50]);
void test (char *(*results)[50]);
are all equivalent prototypes for the function that you are looking for.
Suplement: If you want to use the same function for arrays with varying lenght for the dimension you'd have to use VLA (variable length array) as function arguments:
void test (size_t n, char *results[n][n]);
void test (size_t n, char *results[][n]);
void test (size_t n, char *(*results)[n]);
This only works if you have a compiler that is conforming to C99.
Observe that the parameter for the size comes before the array, such that it is known there.
Also you don't have to declare the arrays themselves with variable length to use this feature for the function parameters. But if you do be careful that you don't allocate large matrices on the stack, otherwise you may easily have a stackoverflow.
If you declare an array as
char *array[N][M];
and pass it to a function as
test(array)
then the prototype to the function will need to be either
void test(char *(*arr)[M])
or
void test(char *arr[][M])
In either case, arr has type "pointer to M-element array of pointer to char". This is not the same type as char ***, and there's no really good or clean way to convert between the two.
Had you allocated dynamcally allocated array in the following manner, then the prototype would be correct:
char ***array = malloc(sizeof *array * N);
if (array)
{
size_t i;
for (i = 0; i < N; i++)
{
array[i] = malloc(sizeof *array[i] * M);
if (array[i])
{
size_t j;
for (j = 0; j < M; j++)
{
array[i][j] = some_initial_pointer_value();
}
}
}
}
Note that in this case, the type of array is char ***.
If you're working with arrays declared as T a[M][N], and you want to write a function that will accept arrays of different sizes, then you can either use the VLA syntax as suggested by Jens, or you could do something like this:
void test(char **a, size_t rows, size_t cols)
{
size_t i, j;
...
some_pointer_value = a[i * rows + j];
...
a[i * rows + j] = some_pointer_value;
}
...
test(&array[0][0], 50, 50);
In this case, we explicitly pass the address of the first element of the array and the array dimensions as separate parameters. Within the body of test we treat the array as having 1 dimension (char *a[rows * cols]) and compute the offset manually. Note that this only works for arrays that are contiguously allocated; this won't work with the version that does piecemeal allocation for each row in the array above.
My C is a little rusty but:
char *params[][];
is a 2D array of char * pointer, not char. If you wanted a 2D char array it is defined as:
char params[valuex][valuey];
Iit will be static memory allocation, only available in definition scope, i mean you leave the scope you loose the array if it is not the behaviour you are looking for try dynamic allocation).
You can then pass this array to a function by defining the function prototype as:
void foo(char param[valuex][valuey] );
Regards
Here is the piece of codes where I don't understand
#include "malloc.h"
/*some a type A and type for pointers to A*/
typedef struct a
{
unsigned long x;
} A, *PA;
/*some a type B and type for pointers to B*/
typedef struct b
{
unsigned char length;
/*array of pointers of type A variables*/
PA * x;
} B, *PB;
void test(unsigned char length, PB b)
{
/*we can set length in B correctly*/
b->length=length;
/*we can also allocate memory for the array of pointers*/
b->x=(PA *)malloc(length*sizeof(PA));
/*but we can't set pointers in x*/
while(length!=0)
b->x[length--]=0; /*it just would not work*/
}
int main()
{
B b;
test(4, &b);
return 0;
}
Can anyone elaborate conceptually to me why we can't set pointers in array x in test()?
On the last line of test() you are initializing the location off the end of your array. If your length is 4, then your array is 4 pointers long. b->x[4] is the 5th element of the array, as the 1st is b->x[0]. You need to change your while loop to iterate over values from 0 to length - 1.
If you want to set to null every PA in b->x, then writing --length instead of length-- should do the job.
Obviously trying to figure out where the -- belongs is confusing. You better write:
unsigned i;
for (i = 0; i < length; i++)
b->x[i] = 0;
But in fact, in this case, you could simply use:
memset(b->x, 0, length*sizeof(PA));
Your structure is more complicated by one level of dynamic memory allocation than is usually necessary. You have:
typedef struct a
{
unsigned long x;
...and other members...
} A, *PA;
typedef struct b
{
unsigned char length;
PA * x;
} B, *PB;
The last member of B is a struct a **, which might be needed, but seldom is. You should probably simplify everything by using:
typedef struct a
{
unsigned long x;
} A;
typedef struct b
{
unsigned length;
A *array;
} B;
This rewrite reflects a personal prejudice against typedefs for pointers (so I eliminated PA and PB). I changed the type of length in B to unsigned from unsigned char; using unsigned char saves on space in the design shown, though it might conceivably save space if you kept track of the allocated length separately from the length in use (but even then, I'd probably use unsigned short rather than unsigned char).
And, most importantly, it changes the type of the array so you don't have a separate pointer for each element because the array contains the elements themselves. Now, occasionally, you really do need to handle arrays of pointers. But it is relatively unusual and it definitely complicates the memory management.
The code in your test() function simplifies:
void init_b(unsigned char length, B *b)
{
b->length = length;
b->x = (A *)malloc(length*sizeof(*b->x));
for (int i = 0; i < length; i++)
b->x[i] = 0;
}
int main()
{
B b;
init_b(4, &b);
return 0;
}
Using an idiomatic for loop avoids stepping out of bounds (one of the problems in the original code). The initialization loop for the allocated memory could perhaps be replaced with a memset() operation, or you could use calloc() instead of malloc().
Your original code was setting the pointers in the array of pointers to null; you could not then access any data because there was no data; you had not allocated the space for the actual struct a values, just space for an array of pointers to such values.
Of course, the code should either check whether memory allocation failed or use a cover function for the memory allocator that guarantees never to return if memory allocation fails. It is not safe to assume memory allocation will succeed without a check somewhere. Cover functions for the allocators often go by names such as xmalloc() or emalloc().
Someone else pointed out that malloc.h is non-standard. If you are using the tuning facilities it provides, or the reporting facilities it provides, then malloc.h is fine (but it is not available everywhere so it does limit the portability of your code). However, most people most of the time should just forget about malloc.h and use #include <stdlib.h> instead; using malloc.h is a sign of thinking from the days before the C89 standard, when there was no header that declared malloc() et al, and that is a long time ago.
See also Freeing 2D array of stack; the code there was isomorphic with this code (are you in the same class?). And I recommended and illustrated the same simplification there.
I just added a printf in main to test b.length and b.x[] values and everything's work.
Just added it like that printf("%d, %d %d %d %d", b.length, b.x[0], b.x[1], b.x[2], b.x[3]); before the return.
It gaves 4, 0, 0, 0, 0 which is I think what you expect no? Or it is an algorithmic error
I assume you are trying to zero all of the unsigned longs inside the array of A's pointed to within B.
Is there a precedence issue with the -> and [] operators here?
Try:
(b->x)[length--] = 0;
And maybe change
typedef struct a
{
unsigned long x;
} A, *PA;
to
typedef struct a
{
unsigned long x;
} A;
typedef A * PA;
etc
It's been a long since I don't use C language, and this is driving me crazy. I have an array of structs, and I need to create a function which will copy one array to another (I need an exact copy), but I don't know how to define the function call. I guess I need to use pointers, but when I try it gives me an error.
struct group{
int weight;
int x_pos;
int y_pos;
int width;
int height;
};
struct group a[4];
struct group b[4];
copySolution(&a, &b);
That last declaration send me an error. As I said, it's been a long since programming in C, so I'm a bit lost right now :(
That should do it:
memcpy(&b, &a, sizeof(a));
EDIT: By the way: It will save a copy of a in b.
As Johannes Weiß says, memcpy() is a good solution.
I just want to point out that you can copy structs like normal types:
for (i=0; i<4; i++) {
b[i] = a[i]; /* copy the whole struct a[i] to b[i] */
}
This has a feel of poorly masqueraded homework assignment... Anyway, given the predetermined call format for copySolution in the original post, the proper definition of copySolution would look as follows
void copySolution(struct group (*a)[4], struct group (*b)[4])
{
/* whatever */
}
Now, inside the copySolution you can copy the arrays in any way you prefer. Either use a cycle
void copySolution(struct group (*a)[4], struct group (*b)[4])
{
const struct group *pb, *pbe;
struct group *pa;
for (pa = *a, pb = *b, pbe = pb + sizeof *b / sizeof **b;
pb != pbe;
++pa, ++pb)
*pa = *pb;
}
or use memcpy as suggested above
void copySolution(struct group (*a)[4], struct group (*b)[4])
{
memcpy(b, a, sizeof *b);
}
Of course, you have to decide first which direction you want your arrays to be copied in. You provided no information, so everyone just jumped to some conclusion.
In my case previous solutions did not work properly! For example,
#Johannes Weiß's solution did not copy "enough" data (it copied about half of the first element).
So in case, somebody needs a solution, that will give you correct results, here it is:
int i, n = 50;
struct YourStruct *a, *b;
a = calloc(n, sizeof(*a));
b = malloc(n * sizeof(*b));
for (i = 0; i < n; ++i) {
// filling a
}
memcpy(b, a, n * sizeof(*a)); // <----- see memcpy here
if (a != NULL) free(a);
a = calloc(n*2, sizeof(*a));
memcpy(a, b, n * sizeof(*b)); // <------ see memcpy here again
Some notes, I used calloc for a, because in the '// filling a' part I was doing operations that required initialized data.
The compiler has no information about the size of the array after passing them as pointer into a function. So you often need a third parameter: The size of the arrays to copy.
A solution (without any error checking) could be:
void copySolution(struct group* a, struct group* b, size_t size) {
memcpy(a, b, size * sizeof(*a));
}
The easiest way is probably
b=a
although a solution with memcpy() will also work.