Index of element pointed to by pointer - c

I have a 2D char array declared as
char A[100][100]
I also have a pointer that points to one element of that array
char *ptr;
ptr = A[5]
This pointer gets passed to another function, which needs to be able to know the index of that pointer (in this case, 5)
void func(void *ptr) {
int index = ???
}
How can I do this? Is this even possible?

Yes it is possible if you can see A in func (A is just a doubly-indexed 1D array, not a pointer on arrays, that's why it is possible).
#include <stdio.h>
char A[100][100];
void func(void *ptr) {
char *ptrc = (char*)ptr;
printf("index %d\n",int((ptrc-A[0])/sizeof(A[0])));
}
int main()
{
char *ptr = A[5];
func(ptr);
}
result:
index 5
of course, if you pass an unrelated pointer to func you'll have undefined results.
Note: it is required to cast the incoming void * pointer to char * or the compiler won't let us diff pointers of incompatible types.
EDIT: as I was challenged by chqrlie to compute both indexes, I tried it and it worked (also added safety to prevent the function being called with an unrelated pointer):
#include <stdio.h>
#include <assert.h>
char A[100][100];
void func(void *ptr)
{
char *ptrc = (char*)ptr;
ptrdiff_t diff = (ptrc-A[0]);
assert(0 <= diff);
assert(diff < sizeof(A));
printf("index %d %d\n",(int)(diff/sizeof(A[0])),(int)(diff % sizeof(A[0])));
}
int main()
{
char *ptr = &(A[5][34]);
func(ptr);
}
result:
index 5 34

You can compute the offset of ptr from the beginning of the array and derive the coordinates:
#include <stdio.h>
#include <stdlib.h>
char A[100][100];
void func(void *ptr) {
if (ptr == NULL) {
printf("ptr = NULL\n");
return;
}
ptrdiff_t pos = (char *)ptr - A[0];
if (pos < 0 || pos > (ptrdiff_t)sizeof(A)) {
printf("ptr points outside A: ptr=%p, A=%p..%p\n",
ptr, (void*)A, (void*)&A[100][100]);
} else {
printf("ptr = &A[%d][%d]\n",
(int)((size_t)pos / sizeof(A[0])), // row number
(int)((size_t)pos % sizeof(A[0]))) // column number
}
}
int main(void) {
char *ptr = &A[5][3];
func(ptr);
return 0;
}

Related

How to properly replace day in a dynamically allocated C array

I am working on a basic framework to dynamically allocate array with the C language. I have created a function to create an array of strings titled init_string_vector. Data can be appended to the array with the append_string_vector function and data can be de-allocated from the heap with the free_string_array function. I am currently working on a function titled replace_string_vector_index that allows a user to pass an array index to the function as well as a pointer to the string array. If the array is typed as a STRING array and the index is not out of bounds, the function should replace the existing data with the string that a user passes to the function.
The replace_string_vector_index function appears to work properly and does replace the string at the index with the other string the user passed to the function. However, the free_string_array function no longer works once I have used to replace_string_vector_index function to act on the array. This makes me think that the process within the function is causing an issue, but I cannot see how. An example is shown below. When the free_string_array function fails, I get the following error, free(): invalid pointer.
vector.h
#ifndef ARRAY_H
#define ARRAY_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef enum
{
FLOAT,
DOUBLE,
CHAR,
INT,
STRING
} dat_type;
// --------------------------------------------------------------------------------
typedef struct
{
char **array;
size_t len;
int elem;
dat_type dat;
} StringVector;
// --------------------------------------------------------------------------------
int string_vector_mem_alloc(StringVector *array, size_t num_indices);
// --------------------------------------------------------------------------------
StringVector init_string_vector();
// --------------------------------------------------------------------------------
int append_string_vector(StringVector *s, char *value);
// --------------------------------------------------------------------------------
void free_string_array(StringVector *array);
// --------------------------------------------------------------------------------
int replace_string_vector_index(StringVector *array, int index, char string[]);
// --------------------------------------------------------------------------------
vector.c
#include "vector.h"
int string_vector_mem_alloc(StringVector *array, size_t num_indices) {
// Determine the total memory allocation and assign to pointer
void *pointer;
pointer = malloc(num_indices * array->elem);
// If memory is full fail gracefully
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(pointer);
return 0;
}
// Allocate resources and instantiate Array
else {
array->array = pointer;
array->len = 0;
return 1;
}
}
// --------------------------------------------------------------------------------
StringVector init_string_vector() {
StringVector array;
array.dat = STRING;
array.elem = sizeof(char *);
string_vector_mem_alloc(&array, array.elem);
return array;
}
// --------------------------------------------------------------------------------
int append_string_vector(StringVector *array, char *value) {
value = strdup(value);
if (!value) {
return -1;
}
array->len++;
char **resized = realloc(array->array, sizeof(char *)*array->len + 1);
if (!resized) {
free(value);
return -1;
}
resized[array->len-1] = value;
array->array = resized;
return 0;
}
// --------------------------------------------------------------------------------
void free_string_array(StringVector *array) {
if (array != NULL) {
for (int i = 0; i < array->len; i++) {
free(array->array[i]);
}
}
free(array->array);
// Reset all variables in the struct
array->array = NULL;
array->len = 0;
array->elem = 0;
}
// --------------------------------------------------------------------------------
int replace_string_vector_index(StringVector *array, int index, char string[]) {
if (array->dat != STRING) {
printf("Array data type must be a STRING");
return 0;
}
if (index > array->len) {
printf("Index is greater than array length");
return 0;
}
* (char **) ((char *) array->array + index * array->elem) = string;
return 1;
}
// --------------------------------------------------------------------------------
main.c
#include <stdio.h>
#include "vector.h"
int main(int argc, const char * argv[]) {
StringVector arr_test = init_string_vector();
char one[] = "Hello";
char two[] = "World";
char three[] = "Hello";
char four[] = "Goodbye";
append_string_vector(&arr_test, one);
append_string_vector(&arr_test, two);
append_string_vector(&arr_test, three);
append_string_vector(&arr_test, four);
// I can free the array at this point
free_string_array(&arr_test)
StringVector arr_test = init_string_vector();
append_string_vector(&arr_test, one);
append_string_vector(&arr_test, two);
append_string_vector(&arr_test, three);
append_string_vector(&arr_test, four);
replace_string_vector_index(&arr_test, 1, one);
// - Once I envoke replace_string_vector_index, free_string_array
// no longer works, and I get an invalid pointer error.
free_string_array(&arr_test);
}
If I understand the requirements for your replace_string_vector_index function, you should first free the memory of array->array[index], then assign the result of strdup(string) to that element.
No casting needed, no complex pointer arithmetic. Just simply:
free(array->array[index]);
array->array[index] = strdup(string);
What happens now (I think) is that you make array->array[index] point to the array that contains the string (i.e. you forget the strdup step). An array that wasn't allocated by malloc, and which can't be passed to free.
Since you will pass it to free as part of free_string_array you will have undefined behavior.

How to assign a pointer to a list and print it out in c?

I've managed to point towards an array, however, the closest I've gotten to pointing to a char* list only prints out the individual letters as shown below:
#include <stdio.h>
main()
{
char* list[2];
list[0] = "Hullo";
list[1] = "GoodBye";
char* pointer = &(list);
char* back = *(list);
printf("%c", back[8]);
}
0 through 4 of back prints out "Hullo", 5 through 7 is whitespace, and 8 through 14 prints out "Goodbye".
I'm wondering how I can avoid printing this list character to character, as it becomes a very inconvenient issue when returning lists of unspecified sizes and planning on using them for another function etc.
It feels like you're looking for:
#include <stdio.h>
int
main(void)
{
char * list[2];
list[0] = "Hullo";
list[1] = "GoodBye";
char ** pointer = list;
for( size_t i = 0; i < sizeof list / sizeof *list; i++ ){
printf("%s\n", *pointer++);
}
}
but maybe you're looking for something like:
#include <stdio.h>
#include <stdlib.h>
char **
foo(void)
{
char **p = malloc(3 * sizeof *p);
if( p == NULL ){
perror("malloc");
exit(1);
}
p[0] = "Hullo";
p[1] = "GoodBye";
p[2] = NULL;
return p;
}
int
main(void)
{
char **p = foo();
for( ; *p; p++ ){
printf("%s\n", *p);
}
free(p);
}

How to properly use realloc in c? [duplicate]

This question already has answers here:
How can I create a dynamically sized array of structs?
(10 answers)
Closed 4 years ago.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define LENGHT 20
typedef struct {
unsigned id;
char name[LENGHT];
char genre[LENGHT];
char nazionality [LENGHT];
int year_carrier_started;
bool check;
}Artist;
void print(Artist *arr, int *i);
void addOne(Artist *arr, int *i);
int main(void) {
int index = 5;
Artist *array = malloc(sizeof(int)*index);
for (int i=0;i<index;i++)
{
printf("Insert a number:\n");
scanf("%d",&array[i].id);
}
do
{
addOne(array,&index);
print(array,&index);
}while(1);
system("pause");
free(array);
return EXIT_SUCCESS;
}
void addOne(Artist *arr, int *i)
{
realloc(arr,sizeof(Artist)*(*i)+1);
printf("Insert another one:\n");
scanf("%d",&arr[*i].id);
*i = *i +1;
print(arr,i);
}
void print(Artist *arr, int *i)
{
for (int j=0;j<*i;j++)
{
printf("Number: %d position %d\n",arr[j].id,j);
}
}
Hi guys, I got this struct from a piece of my program, what I need to is to realloc everytime the user wants to add a new Artist. After adding like 10/15 more users, it crashes for no reason (at least for me there is not). What am I doing wrong? (Dat *i is passed by reference, it counts how many artists are there already).
How to properly use realloc in c(?)
After adding like 10/15 more users, it crashes for no reason
#Christian Gibbons well advises: use the return value of realloc(). The former value of array may not be valid.
Multiply the right values
// sizeof(Artist)*(*i)+1
sizeof(Artist)*((*i)+1)
Use the return value of realloc()
// realloc(array,sizeof(Artist)*(*i)+1);
void *new_ptr = realloc(array,....
Check realloc() results
// realloc(array,sizeof(Artist)*(*i)+1);
void *new_ptr = realloc(array,....
if (new_ptr == NULL) OutOfMemory();
else array = new_ptr;
Consider sizing by the object than the type
// realloc(array,sizeof(Artist)*(*i)+1);
void *new_ptr = realloc(array, sizeof *array *((*i)+1));
All together
Artist *array = malloc(sizeof *array);
if (array == NULL) Handle_OutOfMemory();
...
void *new_ptr = realloc(array, sizeof *array * ((*i)+ 1));
if (new_ptr == NULL) {
// `array` still has *i elements assigned to it.
Handle_OutOfMemory();
} else {
array = new_ptr;
(*i)++;
}
realloc will attempt to resize your allocated memory in place if it can, but if there's not enough room to expand to the new size where it is, it will have to move the data to a new location. Realloc returns a pointer to the location for this reason. You should also test to make sure that it did not err. So something like this:
Artist *arr = malloc(sizeof(*arr) * i);
Artist *temp = realloc(arr, sizeof(Artist)*((*i)+1) // Borrowing this from Yunnosch
if(temp) {
arr = temp;
}
else {
free(arr);
// more error handling
}

C Program: Update unsigned char pointer array with function

I have a function to update an unsigned char* and cannot find where my bug is. I'm not sure if I need to allocate memory, or if I am pointing to the wrong memory space somewhere. I tried to follow a similar structure as posted here, but have not had success with an unsigned char.
My code so far:
#include <stdio.h>
void changeArray(unsigned char **arr)
{
unsigned char ptr[3] = {100, 101, 102};
*arr = ptr;
printf("%d\n", **(arr+0)); // This prints out the correct value of 100
}
int main(int argc, const char* argv[])
{
int i = 0;
unsigned char *blah;
unsigned char ptr2[3] = {103, 104, 105};
blah = ptr2;
printf("Blah is: \n");
for (i = 0; i < 3; i++) {
printf("%d,",*(blah+i)); //This prints out 103,104,105
}
changeArray(&blah);
printf("Blah is now: \n");
for (i = 0; i < 3; i++) {
printf("%d,", *(blah +i)); //This prints out 0,0,0
}
return 0;
}
Any help in determining how to properly access the values set in the changeArray() function would be greatly appreciated.
With this *arr = ptr; you are storing a pointer to a variable with automatic storage duration. The behaviour undefined.
You can dynamically allocate and return a pointer that way:
void changeArray(unsigned char **arr)
{
unsigned char ptr[3] = {100, 101, 102};
unsigned char *p = malloc(sizeof ptr);
memcpy(p, ptr, sizeof ptr);
*arr = p;
printf("%d\n", **(arr+0)); // This prints out the correct value of 100
}
You should also do error checking if malloc failed and remember to free the allocated memory after use in main.
The problem here is, ptr is local to changeArray() function. So once the function finishes execution, there is no existance of ptr. Hence, once you assign ptr to *arr
*arr = ptr;
and changeArray() execution gets over, accessing blah in main() now will invoke undefined behaviour.
FWIW, you don't need to pass the address of blah, you don't need a pointer-to-pointer at all. blah is already a pointer, which you can pass to changeArray() to alter the contents of the memory area it points to. You can do something like
void changeArray(unsigned char *arr)
{
for (int i = 0; i < 3; i ++)
arr[i] = 100+i;
}
and call it like
changeArray(blah);

Initializing values at the end of a pointer to pointer to pointer chain

Alright I've been cranking away at this all day (not hw), and though it may not be a particularly useful bit of code, it is a neat conceptual thing. I am trying to figure out the best way to set a value at the end of, for lack of a better name, a pointer to pointer to pointer chain. For example, I declare:
int *****ptr;
What is the best way to set each pointer to pointer segment, all the way down to the actual int value?
This code doesn't compile because it doesn't like the way I use and dereference void pointers:
#include <stdio.h>
#include <stdlib.h>
#define NUMPOINTERS 5
int main(int argc, char **argv)
{
int *****number;
*****number = malloc(sizeof(void*));
void *ptr = *number;
int i;
for(i = 1; i < NUMPOINTERS; i++)
{
if(i == NUMPOINTERS - 1)
{
ptr = malloc(sizeof(int));
int *iPtr = (int*)ptr;
*iPtr = 900;
break;
}
*ptr = malloc(sizeof(void*));
ptr = **ptr;
}
printf("%d", *****number);
return 0;
}
Is there some article out there that talks about ridiculous numbers of pointers to pointers and how to work with them?
What you have is pretty close. You probably want to work from the inside out, though. Here's a complete example based on your program (comments inline):
#include <stdio.h>
#include <stdlib.h>
#define NUMPOINTERS 5
int main(void)
{
void *ptr = malloc(sizeof(int)); // allocate space for the integer value
*(int *)ptr = 900; // initialize it
// iterate to create the nested pointers
for (int i = 1; i < NUMPOINTERS; i++)
{
void **newptr = malloc(sizeof(void *)); // create a new pointer
*newptr = ptr; // point it at what we have so far
ptr = newptr; // "step out" one level
}
int *****number = ptr; // make our 'int *****' pointer
printf("%d\n", *****number); // dereference and print the pointed-to value
return 0;
}

Resources