C Program: Update unsigned char pointer array with function - c

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);

Related

How to reverse every string in an array of strings through a function in C?

I have been trying to solve this issue for whole day, and could not do it on my own. Searching the internet didn't help me solve it either
So, this the function prototype:
void invert(char **arr, int n);
First argument is an array of strings, and the second one is number of strings in an array.
This is my code:
#include <stdio.h>
#include <string.h>
void invert(char** arr, int n)
{
int i, j, len;
for(j=0;j<n;j++)
{
len=strlen(arr[j]);
for(i=0;i<len/2;i++)
{
char tmp = arr[j][i];
arr[j][i] = arr[j][len - i - 1];
arr[j][len - i - 1] = tmp;
}
}
}
int main()
{
int n=3, i;
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
}
The code breaks when it reaches the line:
arr[j][i] = arr[j][len - i - 1];
and I can't figure out why.
The function receives an array of strings perfectly (tested it with some printf statements for characters of specific strings), and the char tmp succesfully recieves a correct character, but the program crashed when it reaches the line mentioned earlier. Printf statements after that line don't work.
Did I miss anything? Can someone explain what am I doing wrong? Thank you!
For starters this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invokes undefined behavior because the pointer arr is uninitialized and has an indeterminate value.
Moreover this approach in any case is wrong because you may not change string literals.
What you need is to declare a two-dimensional array as for example
enum { N = 11 };
//...
char arr[3][N] =
{
"John", "Doe", "Programmer"
};
In this case the function declaration will look like
void invert( char arr[][N], int n );
The enumeration must be declared before the function declaration.
Instead of the two-dimensional array you could declare an array of pointers like
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
In this case the function declaration may be as shown in your question
void invert(char** arr, int n)
So what you need to do with minimal changes is to substitute this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
for this code snippet
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
To begin with, what you have here:
char **arr;
is a pointer to pointer to char.
Secondly, even if you had an array of pointers to char, like so :
char *arr[3];
And then assigning each string literal :
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
would still invoke Undefined behavior, since you are attempting to modify a string literal which is read only.
What you need is, either a 2D array of chars :
char arr[][100] = {"John", "Doe", "Programmer"};
and also change the function signature to :
void invert(char arr[][100], int n)
or you have to dynamically allocate memory and use a function like strcpy(), strdup(), memcpy() etc :
char **arr;
arr = malloc(n * sizeof(char *)); // or sizeof(*arr)
if (arr == NULL) {
fprintf(stderr, "Malloc failed to allocate memory\n");
exit(1);
}
arr[0] = strdup("John"); // good idea to also check if strdup returned null
arr[1] = strdup("Doe");
arr[2] = strdup("Programmer");
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
for (i = 0; i < 3; i++) {
free(arr[i]);
}
free(arr);

Where should I use a type char ** in some case as the input parameter?

There is some code piece right here below:
main ()
{
char in[8];
char out[255];
iconv_t cd;
cd = iconv_open("gb18030", "utf-8");
...
char *p_in = in;
char *p_out = out;
size_t inlen = strlen(in);
size_t outlen = sizeof(out);
if (iconv(cd, &p_in, &inlen, &p_out, &outlen) < 0)
{
...
return -1
}
...
return 0;
}
I can't totally understand the 2nd and 3rd parameters of the call to iconv. Why should that be ** pointer not the * pointer as the input? Can anyone explain the cases in C when the ** pointer should be used?
Pointer to pointer is used where the passed pointer is need to be modified in the called function and that modification need to be seen in the caller function. This is required because in C arguments are passed by value. So, when an argument is passed to a function then it simply copied to the function's parameter and created a local copy having block scope. Any change to that variable will not be seen in the argument that has been passed.
void foo(in x){
x = 10;
}
int main(void){
int x = 5;
foo(x)
printf("%d\n", x); // x will be 5
}
Same happens with pointers
void bar(char *p){
p = "foobar";
}
int main(void){
char *p = NULL;
bar(p);
if(p)
printf("p is pointing to %s\n", p);
else
printf("p is NULL\n"); // This will
}
Using a pointer to pointer will do the desired job (pointing p to the string "foobar"
void bar(char **p){
*p = "foobar";
}
int main(void){
char *p = NULL;
bar(&p);
if(p)
printf("p is pointing to %s\n", p);
else
printf("p is NULL\n"); // This will
}
Another use is when an array of string is need to passed to a function. Like
int main(int argc, char **argv)
or
void print_fruits(char **fruits, size_t len){
for(int i = 0; i < len; i++)
printf("%s\n", fruits[i]);
}
int main(void){
char *fruits[5] = {"Apple", "Banana", "Cherry", "Kiwi", "Orange"};
print_fruits(fruits, sizeof(fruits)/sizeof(fruits[0]));
}
Note that in function call print_fruits, fruits in the argument list will decay to pointer to its first element and the expression fruits will become of type char ** after the conversion.

C pointer address changes without assignment

I am working on a Uni assignment here, and I've run into a problem. I am attempting to store a string input at a point inside a struct using a for-loop. Later on I intend to use the pointer to the place where the data was stored to fetch the string. Now the problem is, as I move on inside my for-loop, the address of the point changes as well. This code:
printf("B: %p\n", txt->point);
for(i = 0; i < input_sz; i++)
{
txt->point[i] = input[i];
}
printf("A: %p\n", txt->point);
gives the output:
B: 0x7fc111803200
A: 0x7fc111803265
where B is before-value and A is after-copying value.
Any help debugging this would be very appreciated!
EDIT: Here's some more code:
The struct:
struct text_storage {
char* start;
char* point;
char* end;
} typedef text_t;
Initialization function:
text_t* text_init(void *memory, size_t size)
{
text_t* to_return;
if(size < sizeof(text_t))
{
return NULL;
}
to_return = (text_t*) memory;
to_return->start = to_return;
to_return->end = to_return->start + size;
to_return->point = to_return->start;
printf("Start: %p, point: %p, end: %p, end-start: %d\n", to_return->start, to_return->point, to_return->end, (to_return->end - to_return->start));
return to_return;
}
The text-store method in which the error occurs:
int text_store_entry(text_t *txt, const char *input, size_t input_sz)
{
int to_return;
char* begin = txt->point;
int i;
if(input_sz > (txt->end - txt->point))
{
return -1;
}
printf("Start: %p, point: %p, end: %p, end-start: %d\n", txt->start, txt->point, txt->end, (txt->end - txt->start));
printf("B: %p\n", txt->point);
for(i = 0; i < input_sz; i++)
{
txt->point[i] = input[i];
}
printf("A: %p\n", txt->point);
}
Main-function (testing purposes only):
int main(int argc, char* argv[])
{
void* memory = malloc(10000);
char* a = "hei pa deg din trekkbasun";
text_t* txt;
int memoverwritten;
txt = text_init(memory, 10000);
memoverwritten = text_store_entry(txt, a, (size_t)26);
printf("got through\n");
return 0;
}
The problem most probably is due to the initialization of structures of type struct text_storage. Such structures contain three pointers to text. Each pointer should be initialized, possibly with a malloc. Your text_init function does not do that properly.
In fact, the place where the start pointer is stored overlaps with the first bytes of the memory that you want to use.
I'm guessing that you need a structure like this:
typedef struct text_storage {
char* start;
char* point;
char* end;
char* data;
} text_t;
initialized with a function like this:
text_t text_init(void *memory, size_t size)
{
text_t to_return;
to_return.data = (char *) memory;
to_return.start = to_return.data;
to_return.end = to_return.start + size;
to_return.point = to_return.start;
return to_return;
}
Print txt->point in the loop and see the point at which it changes. I'm guessing it changes when assigning to txt->point[0]. I'm not fully familiar with printf, so I'm not sure what it's printing out for you, but the name of an array references the first location. If printf is printing out a pointer, txt->point[i] is always a char pointer, and printf may be dereferencing txt->point, which will get it the first entry, and then showing the address there, which you do assign when you change the point to input[i].

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;
}

Storing chars into a string with a for loop?

I have this function, bits_show, which prints to stdout a 2-3 bit long code.
void bits_show(bits *a)
{
int i;
for (i = 0; i < a->next; i++)
putchar(a->bits[i]);
}
where bits:
struct bits {
int capacity;
int next;
char *bits;
};
I am trying to write a function, char* bits_char(bits a) that captures these characters and collects them into a single char file.
This is what I have so far, but it keeps spitting errors:
char* bits_char(bits *a)
{
char* str = (char*) malloc( sizeof(a->next * char));
int i;
for (i=0; i<a->next; i++){
str[i] = (a->bits[i]);
}
return str;
}
"bits.c: In function ‘bits_char’:
bits.c:33: error: variable-sized object may not be initialized
bits.c:37: warning: function returns address of local variable"
This is wrong:
sizeof(a->next * char)
I presume you meant to write:
a->next * sizeof(char)
But since sizeof(char) equals 1 by definition you would simply omit that.
But even that is wrong since you need to allow space for the null terminator which your code does not currently write. The allocation needs to be:
malloc(a->next+1)
And add the null-terminator like this:
str[a->next] = 0;
All in all, the finished product is as so:
char* bits_char(bits *a)
{
char* str = malloc(a->next+1);
int i;
for (i=0; i<a->next; i++){
str[i] = (a->bits[i]);
}
str[a->next] = 0;
return str;
}
I removed the cast of the return value of malloc which is not needed in C.
And you should also ensure that you check the return value of malloc for a failed allocation. It will return the null pointer if it fails. I've not shown how to do that because I don't know your error handling policy.

Resources