Generic copy using void pointer - c

I implemented a generic quick sort and now I want to accept the array from command line. Following is a function that is supposed to copy character pointers from array argv to base. I am getting segmentation fault. The copy is working fine when I pass address of two integers.
#include<stdio.h>
void copy(void *src, void *dest, int size)
{
char *s, *d;
int i;
s = src;
d = dest;
for(i = 0; i < size; i++)
d[i] = s[i];
}
int main(int argc, char *argv[])
{
void *base;
int i = 10;
int j = 20;
printf("%d, %d\n", i, j);
copy(&i, &j, sizeof(int));
printf("%d, %d\n", i, j);
copy(argv, base, sizeof(char *));
return 0;
}
Output
10, 20
10, 10
Segmentation fault (core dumped)

argv is a pointer array. If you just want to copy the pointers you can do it like that:
base = calloc( argc, sizeof(char *) );
copy( argv, base, argc * sizeof(char *) );
Now you have copy of the pointer array argv, but that still contains pointers to the original arguments argv[i].
If you want to create copies of argv[i] too, dont use copy() but:
char **base = calloc( argc, sizeof(char *) );
int i;
for( i=0; i<argc; i++ )
base[i] = strdup( argv[i] );
But remember: argv[0] is the program's name and I would bet you don't want that to be part of the array. To avoid it:
base = calloc( argc-1, sizeof(char *) );
copy( argv+1, base, (argc-1) * sizeof(char *) );
or
char **base = calloc( argc, sizeof(char *) );
int i;
for( i=1; i<argc; i++ )
base[i-1] = strdup( argv[i] );

You are trying to copy sizeof(char*) bytes to where base is pointing to. But you did not allocate any memory to base so the program invokes undefined behaviour.

void *base = malloc(strlen(argv[0])+1);
then
copy(argv[0], base, strlen(argv[0])+1);
at the end
free(base);
sizeof(char*) will return a size of a single pointer, not the whole path
Edit:
void *base;
int i;
if (argc>0)
{
base = malloc(argc+1);// we have enough pointers for copying args (+1 to null terminat it)
for(i=0; i < argc; i++)
{
base[i] = malloc(strlen(argv[i])+1);
copy(argv[i], base[i], strlen(argv[i])+1);
}
base[i] = NULL;
}
base will be a double pointer holding all arguments
you may do
memset(...)
and
memcopy(...) btw

Argv is not a single pointer, its a double pointer,
you should be doing like this:
base = calloc(1, sizeof(char *));
copy(argv[1], base, sizeof(char *));
if you really want to copy the full argv, you have to replace
the sizeof(char *) with strlen(argv[0]) and have to allocate base with the length of the argv[0].

Related

Expand a C array inside a function

This works in a main, but breaks when put into a function. I'm not sure how to reassign the pointer after passing into a function.
void expandArray(int** arr[], int* size) {
int *temp;
*temp = *arr;
*arr = (int*) malloc(*size * 2 * sizeof(int));
for (int i = 0; i < *size; i++) {
printf("assigning from temp: %d ", temp[i]);
arr[i] = temp[i];
printf("to arr: %d \n", arr[i]);
}
*size = *size * 2;
free(temp);
}
main(){
int *arr;
arr = (int*) malloc(maxSize * sizeof(int));
if ....
expandArray(arr, &arrSize);
// use bigger arr for other stuff
}
In main, arr is declared as int *arr. When main calls expandArray, it should pass a pointer to arr, which is written &arr and has type int **a.
However, you declared the parameter to expandArray as int **arr[], adding additional brackets. Those are unnecessary and change the type, and your compiler should have warned you about that. Pay attention to compiler warnings. Be sure you understand them, and resolve them before proceeding.
In expandArray, you use both arr[i] and temp[i] to access the array. However, arr[i] is not a correct way to access array elements. When the declaration of the arr parameter is corrected, it will be int **arr, and it will not be proper to refer to an element of the array as arr[i]. It will be (*arr)[i].
Commonly, to make this a little less confusion, authors will use a temporary variable to hold the pointer, so they do not need the extra asterisk:
int *NewArray = malloc(...); // Get new space.
*arr = NewArray; // Send new address to caller.
...
NewArray[i] = temp[i]; // Use temporary variable for access.
Some other points:
When calling malloc, use sizeof *p, where p is the pointer being assigned to, rather than sizeof(int). This is better because, if you later want to change the type for p, it only has to be changed in its declaration, not also in the sizeof. Then there is less likely to be a mistake where it is changed in one place and not another.
Do not cast the result of malloc. This is unnecessary in C, although it is required in C++.
main should be declared as int main(void) or int main(int argc, char *argv[]), not as main(). (C implementations may also provide for other forms.)
Use size_t for sizes of arrays, not int, and either size_t or ptrdiff_t for indices of arrays.
Overall, the code could be:
#include <stdio.h>
#include <stdlib.h>
void expandArray(int **arr, int *size)
{
// Record old pointer and size in temporary variables for convenience.
int *OldArray = arr;
size_t OldSize = *size;
// Prepare new size and pointer.
size_t NewSize = 2 * OldSize;
int *NewArray = malloc(NewSize * sizeof *NewArray);
// Handle allocation failure.
if (!NewArray)
{
fprintf(stderr, "Error, unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
// Copy data from old array to new array.
for (size_t i = 0; i < OldSize; ++i)
NewArray[i] = OldArray[i];
// Send new size and pointer to caller.
*size = NewSize;
*arr = NewArray;
// Release old memory.
free(OldArray);
}
int main(void)
{
int *arr;
arr = malloc(InitialSize * sizeof *arr);
if (...)
expandArray(&arr, &arrSize);
// use bigger arr for other stuff
}
I think the arr sould be int ** type.
void expandArray(int** arr, int* size) {
int *temp;
temp = *arr;
*arr = (int*) malloc(*size * 2 * sizeof(int));
for (int i = 0; i < *size; i++) {
printf("assigning from temp: %d ", temp[i]);
(*arr)[i] = temp[i];
printf("to arr: %d \n", (*arr)[i]);
}
*size = *size * 2;
free(temp);
}
If you just want to expand the array size, you can use realloc.
And the extended area should be initialized using memset.
void expandArray(int** arr, int* size) {
*arr = (int*) realloc(*arr, *size * 2 * sizeof(int));
memset(*arr+*size, 0, *size * sizeof(int));
*size = *size * 2;
}

Code giving runtime error?

i am trying to solve leetcode question :-
https://leetcode.com/problems/largest-number/
Given a list of non negative integers, arrange them such that they form the largest number.
For example, given [3, 30, 34, 5, 9], the largest formed number is 9534330.
i am trying to sort strings by defining comparator to compare strings by concatinating right-to-left or left-to-right.
The program is giving runtime error. Please help....
int comp(const void* a, const void* b){
int p = *((int *)a);
int q = *((int *)b);
int size = 14;
char * first = (char *)malloc(size * sizeof(char));
char * second = (char *)malloc(size * sizeof(char));
first[0] = "\0";
second[0] = "\0";
sprintf(first, "%d",p);
sprintf(first, "%d",q);
sprintf(second, "%d",q);
sprintf(second, "%d",p);
return -1*strcmp(first, second);
}
char* largestNumber(int* nums, int numsSize) {
if(numsSize <=0)
return NULL;
qsort(nums, numsSize, sizeof(int), comp);
char * result = (char*)malloc(numsSize *5*sizeof(char));
int i;
for(i=0; i<numsSize; i++)
result = strcat(result, nums[i]);
return result;
}
Allocating memory with malloc() and throwing it away is a bad practice.
Since you always allocate fixed amount of memory in comp, use regular array.
Don't do first[0] = "\0";, which is assigning an pointer to char variable.
Also remove useless sprintf, whose result is soon be overwritten.
Allocating 5 bytes for each elements may be too small if int has 4 bytes. Allocate more memory.
Initialize the buffer pointed by result before passing it to strcat().
Convert the integer to string before passing it to strcat().
They say that you shouldn't cast the result of malloc() in C.
Possible fix (not tested):
int comp(const void* a, const void* b){
int p = *((int *)a);
int q = *((int *)b);
char first[14];
char second[14];
sprintf(first, "%d", q);
sprintf(second, "%d", p);
return -1 * strcmp(first, second);
}
char* largestNumber(int* nums, int numsSize) {
if(numsSize <= 0)
return NULL;
qsort(nums, numsSize, sizeof(int), comp);
char * result = malloc(numsSize * 14 * sizeof(char));
int i;
result[0] = '\0';
for(i = 0; i < numsSize; i++) {
char num[14];
sprintf(num, "%d", nums[i]);
result = strcat(result, num);
}
return result;
}

Allocating memory for pointer to pointer to pointer in C

I am trying to allocate memory for triple pointer and I cannot make it right. I have pointer to pointer to char
char **words;
allocate(&words);
And I created method for memory allocation:
void allocate(char ***words){
for (int i = 0; i < MAXWORDNUM; ++i)
(*words)[i] = malloc(sizeof(char*) * MAXWORDNUM);
for (int i = 0; i < MAXWORD; ++i)
(**words)[i] = malloc(sizeof(char) * MAXWORD);
}
As I understand I should allocate memory for pointers and then I should allocate memory for each char. For the above code I am getting error:
warning: incompatible pointer to integer conversion assigning
to 'char' from 'void *' [-Wint-conversion]
(**words)[i] = malloc(sizeof(char) * MAXWORD);
How to make it work?
Thank you
void allocate(char ***words){
*words = malloc(sizeof(char*) * MAXWORDNUM);
for (int i = 0; i < MAXWORDNUM; ++i)
(*words)[i] = malloc(MAXWORD);
}
You want an array of pointers, not an array of array of pointers, the first loop is not needed:
void allocate(char ***words){
/* for (int i = 0; i < MAXWORDNUM; ++i) */
/* (m)allocate space for n pointers to words */
*words = malloc(sizeof(char *) * MAXWORDNUM);
for (int i = 0; i < MAXWORDNUM; ++i)
(*words)[i] = malloc(MAXWORD); /* (m)allocate space for each word */
}
int main(void)
{
char **words;
allocate(&words);
return 0;
}
It depends on your purpose, do you intend to create a 2-dimensional array, or a array of pointers, or just a pointer to pointer?
1) A 2-dimensional array
void allocate_two_dimen_array(char ***words, unsigned int x, unsigned int y){
*word = malloc(x * y * sizeof(char));
}
2) A array of char pointers
void allocate_pointer_array(char ***words, unsigned int quantity){
*word = malloc(quantity * sizeof(char*));
}
3) A pure pointer to char pointer
void allocate_pointer_pointer(char ***words){
*word = malloc(sizeof(char**));
}
For practical purposes, for instance: the first one can be used to store a bmp image, the second one is used to store a set of strings
word = {"This is the first line", "This is the second line"};

triple pointers, arrays, and malloc

My code compiles just fine, but I'm still a little rough on the pointer and array concepts. I would appreciate your help very much.
void initialize(int individual_count, int family_count, char ***indiIDs,
char ***names, char ***spousesIDs, char ***childIDs)
//so here I declared two int variables and four triple pointers,
// which are pointer to a pointer to a pointer to an integer, correct?
{
int i;
//malloc allocates memory space and returns the address of the
// first byte to the pointer *indiIDs,right?
(*indiIDs) = (char**)malloc(sizeof(char*) * individual_count);
(*names) = (char**)malloc(sizeof(char*) * individual_count);
for(i = 0; i <individual_count; i++)
{
(*indiIDs)[i] = (char*)malloc(sizeof(char) * 20);
(*names)[i] = NULL;
}
//*indiIDs[i] is an array of pointers, correct? so what exactly
// is the difference between mallocing and returning to *indiIDs
// and then to *indiIDs[i] as seen here?
(*spousesIDs) = (char**)malloc(sizeof(char*) * family_count);
(*childIDs) = (char**)malloc(sizeof(char*) * family_count);
for(i = 0; i < family_count; i++)
{
(*spousesIDs)[i] = (char*)malloc(sizeof(char) * 40);
//since spousesIDs[][] is a 2D array, would *spousesIDs[][]
// indicate a triple array then?
(*spousesIDs)[i][0] = '\0';
(*childIDs)[i] = NULL;
}
}
Your example doesn't show a 3D array, but a 2D array:
void init2D(char * ** x, int w, int h)
{
(*x) = (char**)malloc(sizeof(char*) * w);
for (i=0; i<w; i++) (*x)[i] = (char*)malloc(sizeof(char) * h);
}
The reason it has an additional * as a function parameter, is because C doesn't have pass-by-refence like C++
It's used this way:
void main ()
{
char ** lines = 0;
init2D (&lines, 4, 256); // char[256] x 4
}

Sending a pointer to a pointer by reference

I have been trying to send a pointer to a pointer (we can call it an array of strings, or an array of an array of chars even) to a function, by reference, because I need it to be updated. I don't want to have the function returning the pointer to a pointer (that one I got working) because I want the return to be the size of the array.
This is a working function I created for testing purposes, which returns the pointer to a pointer, and the calling method:
#include <stdio.h>
char **populate_items() {
char **items;
int i;
items = (char **) malloc(sizeof(char*) * 3);
for (i=0; i<3; i++)
*(items+i) = (char *) malloc(sizeof(char) * 10);
items[0] = "1234567890";
items[1] = "2345678901";
items[2] = "3456789012";
return items;
}
int main(int argv, char *argc) {
char **items;
int i;
items = populate_items();
for(i=0; i<3; i++)
printf("%s\n", items[i]);
return 0;
}
This is what I THINK the function and the call to the function that gets the pointer to a pointer as reference should look like, but I get a segmentation fault when trying to print items[1] or items[2]
#include <stdio.h>
populate_items(char ***items) {
int i;
*items = (char **) malloc(sizeof(char*) * 3);
for (i=0; i<3; i++)
*(items+i) = (char *) malloc(sizeof(char) * 10);
*items[0] = "1234567890";
*items[1] = "2345678901";
*items[2] = "3456789012";
}
int main(int argv, char *argc) {
char **items;
int i;
populate_items(&items);
for(i=0; i<3; i++)
printf("%s\n", items[i]);
return 0;
}
In the abstraction that I created in my head, the function should be fine, but off course it's not given that I'm getting a segmentation fault. I already managed to understand how a pointer to a pointer works just fine, but I think I'm having trouble putting my head over how the pointer to a pointer to a pointer concept translates into code.
So what am I missing?
You forgot a dereference and got the precedence of * vs. [] wrong:
populate_items(char ***items) {
int i;
*items = (char **) malloc(sizeof(char*) * 3);
for (i=0; i<3; i++)
*(*items+i) = (char *) malloc(sizeof(char) * 10);
(*items)[0] = "1234567890";
(*items)[1] = "2345678901";
(*items)[2] = "3456789012";
}
Note, however, that the assignments
(*items)[0] = "1234567890";
etc. lose the only handle to the just allocated memory.
you can use as below
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
char*** populate_items(char ***items)
{
int i;
items = (char ***) malloc(sizeof(char*) * 3);
for (i=0; i<3; i++)
*(items + i) = (char **) malloc(sizeof(char) * 10);
**(items + 0) = "1234567890";
**(items + 1) = "2345678901";
**(items + 2) = "3456789012";
return items;
}
int main(int argv, char *argc)
{
char **items;
int i;
char *** res = populate_items(&items);
for(i=0; i<3; i++)
printf("%s\n", **(res + i));
return 0;
}

Resources