changing adress of char array inside a function - arrays

I'm playing with pointers and array and I found it hard to understand why this code doesn't work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void change(char **test)
{
char *test1 = malloc(sizeof(char)*17);
strcpy(test1, "HEAP");
*test = test1;
}
int main()
{
char str[15]= "hello World"; //Array of char
change(&str); // Passing the address of my array of char
printf("%s", str);
}
The goal is to change the address of strto the allocated memory array inside the function change
But changing the line :
char str[15]= "hello World";
to this (which is read only right ?):
char *str= "hello World";
Also, I'm getting a warning when compiling that I don't understand either :
main.c:17:12: warning: passing argument 1 of ‘change’ from incompatible pointer type [-Wincompatible-pointer-types]
17 | change(&str); // Passing the address of my array of char
| ^~~~
| |
| char (*)[15]
main.c:5:20: note: expected ‘char **’ but argument is of type ‘char (*)[15]’
5 | void change(char **test)
Thank you !

char str[15] isn't a pointer so you can't change its address. You need str to be a char*.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HEAP "HEAP"
void change(char **test)
{
char *test1 = malloc(sizeof HEAP); // sizeof(char) is defined to be 1
strcpy(test1, HEAP);
*test = test1;
}
int main()
{
char orig[] = "hello World";
char *str = orig; // initialize it to point at the first char in orig
printf("before: %s\n", str);
change(&str);
printf("after : %s\n", str);
free(str); // free what you've allocated
}

The goal is to change the address of strto the allocated memory array inside the function change...
You cannot change the address of a variable. If a variable is a non-const pointer, you can make it point to some other memory address, provided it should be of compatible type with the type of pointer.
Before moving ahead, a couple of points for array:
Arrays are not pointers. They both are different.
In C, array names are non modifiable lvalues.
The warning message that you are getting is very clearly conveying the message - the type of argument that you are passing to change() function is not compatible with type of its parameter. The type of &str argument (passing to change()) is char (*)[15] and type of test parameter is char **.
Lets change the type of test parameter of change() function and make it compatible with the type of &str that you are passing to change() function and check what happens!
Make the following change in your program
void change(char (*test)[15])
^^^^^^^^^^^
With this change when you compile your program, you will get following error:
# gcc -Wall -Wextra prg.c
prg.c:10:11: error: array type 'char [15]' is not assignable
*test = test1;
~~~~~ ^
1 error generated.
The error is occurring because test is a pointer pointing to str array and when you dereference it (i.e. *test) you get the array of type char [15] and, that means, this statement will end up attempting to assign test1 to array of type char [15] (which, in this context, is array str). Check the second point above - array names are non modifiable lvalues. Hence, this error is occurring.
So, arrays are non assignable, however, you can change the content of array in change() function using the address of str that you passing to change() function. You can do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_CHARS 15
void change(char (*test)[NUM_CHARS]) {
strcpy (*test, "HEAP");
}
int main (void) {
char str[NUM_CHARS]= "hello World"; //Array of char
printf ("Before calling change(), str : %s\n", str);
change (&str); // Passing the address of my array of char
printf ("After calling change(), str : %s\n", str);
return 0;
}
Output:
# ./a.out
Before calling change(), str : hello World
After calling change(), str : HEAP
Note, that same you can achieve with passing the str to change() function, instead of passing address of str (Of course, you have to make respective changes in the change() function as well).
How to make a pointer pointing so some other memory inside a function is already shown in other post (by #Ted Lyngmo).
Follow good programming practice:
Always check the malloc() return.
Make sure to free the dynamically allocate memory once done with it.

Related

(Returning char (*)(255) from a function with incompatible return type 'char **') error in C

I have this code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
static char** testing(FILE *fp)
{
char temp[255];
char data[255][255];
for (int i = 0; !feof(fp); i++)
{
fgets(temp, 255, fp);
strcpy(data[i], temp);
}
for (int i = 0; i < 66; i++)
{
printf("%s", data[i]);
}
return data;
}
int main(int argc, char const *argv[])
{
FILE *fp;
fp = fopen(argv[1], "r");
testing(fp);
}
I want to return the 2D array data but when I compile this, I get the output:
returning 'char (*)[255]' from a function with incompatible return type 'char **' [-Wincompatible-pointer-types] return data;
I don't see what I've done wrong.
Any help would be very much appreciated.
data is two-dimensional array of chars. When 2D array decals to a pointer it has the type of pointer to the char array.
the function should be declared as :
static char (*testing(FILE *fp))[255]
Returning the pointer to local object is dangerous as dereferencing the returned pointer invokes Undefined Behaviour. The local automatic variables stop existing when a function returns. You need to use (a)global variables, (b)static variables or use (c)malloc family functions to allocate the memory.
(a):
char data[255][255];
static char (*testing(FILE *fp))[255]
{
/* ... */
(b):
static char (*testing(FILE *fp))[255]
{
static char data[255][255];
/* ... */
(c):
static char (*testing(FILE *fp))[255]
{
char (*data)[255] = malloc(255 * sizeof(*data));
/* ... */
Your data variable is not allocated dynamically and therefor cannot be used outside your function. You need to return a pointer to a dynamically allocated array to use it outside of it.
Here for more details about heap and stack:
You declared the return value to be a char** which can be interpreted by reading from right to left, so is a pointer to a pointer of type char. While data is a two dimensional array. Returning data as you do, is returning the pointer to data, which the compiler sees as a pointer to a one-dimensional array. That is why you got an incompatible data error. Additionally you have issue with using a locally declared variable which is not visible outside the function so the value returned would result in a protection fault.

execv arguments error - "expected char * const* but argument is of type const char *"

I have a function whose argument is const char *array[]
array[0] is the path, the rest are the arguments and it ends with NULL.
However, if I try to do execv(array[0], array) I get expected char * const* but argument is of type const char *
How do I go about this, and what is the difference between char * const* and const char *?
void start(const char *array[]) {
execv(array[0], array);
}
First, the error message is not copied correctly. If I run your code in GCC it shows this message instead (note the final *):
note: expected ‘char * const*’ but argument is of type ‘const char **’
which makes more sense as the message you show in the question, does not match the code you show. There is a mismatch in level or indirection.
That said, let's look at this part:
and what is the difference between char * const* and const char *?
Actually it is
and what is the difference between char * const* and const char **?
The first is a pointer to a const pointer to a char. The char that is pointed to is not const and might in theory be changed by execv.
The latter is a pointer to a pointer to a const char. This means, the char that is pointed to mustn't be modified. It might be some read-only string literal in ROM. If you pass such a pointer to a function that will try to modify it, it will fail in one way or the other. Therefore you are not allowed to pass a "pointer to const" to a function that does not expect it to be const.
That is what the compiler is telling you.
Now, how can you get rid of that warning...
To silence your compiler you could try to use some cast and cheat about real nature of that parameter.
In the end the problem will stay the same. A function trying to modify your read-only memory will not be working properly.
Instead you need to make a copy of your data:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void start(const char *array[]) {
int i = 0;
// determine number of strings (including NULL)
while (array[i++] != NULL) ;
// Create an array able to hold pointers to copys
char *my_array[i];
// Copy strings into non-const memory
i = 0;
do
my_array[i] = array[i] ? strdup(array[i]) : NULL;
while (array[i++] != NULL);
execv(my_array[0], my_array);
// Free the memory for the copied strings
i = 0;
do
free(my_array[i]);
while (array[i++] != NULL);
}
int main(void)
{
const char *argv[] = {"ls", "ls", NULL};
start(argv);
return 0;
}

Why can't I access a pointer to pointer for a stack array?

Please take a look at the following code. It tries to pass an array as a char** to a function:
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printchar(&test2); // works
printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
The fact that I can only get it to compile by explicitly casting &test2 to char** already hints that this code is wrong.
Still, I'm wondering what exactly is wrong about it. I can pass a pointer to a pointer to a dynamically allocated array but I can't pass a pointer to a pointer for an array on the stack. Of course, I can easily work-around the problem by first assigning the array to a temporary variable, like so:
char test[256];
char *tmp = test;
test[0] = 'B';
printchar(&tmp);
Still, can someone explain to me why it doesn't work to cast char[256] to char** directly?
test is an array, not a pointer, and &test is a pointer to the array. It is not a pointer to a pointer.
You may have been told that an array is a pointer, but this is incorrect. The name of an array is a name of the entire object—all the elements. It is not a pointer to the first element. In most expressions, an array is automatically converted to a pointer to its first element. That is a convenience that is often useful. But there are three exceptions to this rule:
The array is the operand of sizeof.
The array is the operand of &.
The array is a string literal used to initialize an array.
In &test, the array is the operand of &, so the automatic conversion does not occur. The result of &test is a pointer to an array of 256 char, which has type char (*)[256], not char **.
To get a pointer to a pointer to char from test, you would first need to make a pointer to char. For example:
char *p = test; // Automatic conversion of test to &test[0] occurs.
printchar(&p); // Passes a pointer to a pointer to char.
Another way to think about this is to realize that test names the entire object—the whole array of 256 char. It does not name a pointer, so, in &test, there is no pointer whose address can be taken, so this cannot produce a char **. In order to create a char **, you must first have a char *.
Because test is not a pointer.
&test gets you a pointer to the array, of type char (*)[256], which is not compatible with char** (because an array is not a pointer). This results in undefined behavior.
The type of test2 is char *. So, the type of &test2 will be char ** which is compatible with the type of parameter x of printchar().
The type of test is char [256]. So, the type of &test will be char (*)[256] which is not compatible with the type of parameter x of printchar().
Let me show you the difference in terms of addresses of test and test2.
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("x = %p\n", (void*)x);
printf("*x = %p\n", (void*)(*x));
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printf ("test2 : %p\n", (void*)test2);
printf ("&test2 : %p\n", (void*)&test2);
printf ("&test2[0] : %p\n", (void*)&test2[0]);
printchar(&test2); // works
printf ("\n");
printf ("test : %p\n", (void*)test);
printf ("&test : %p\n", (void*)&test);
printf ("&test[0] : %p\n", (void*)&test[0]);
// Commenting below statement
//printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Output:
$ ./a.out
test2 : 0x7fe974c02970
&test2 : 0x7ffee82eb9e8
&test2[0] : 0x7fe974c02970
x = 0x7ffee82eb9e8
*x = 0x7fe974c02970
Test: A
test : 0x7ffee82eba00
&test : 0x7ffee82eba00
&test[0] : 0x7ffee82eba00
Point to note here:
The output (memory address) of test2 and &test2[0] is numerically same and their type is also same which is char *.
But the test2 and &test2 are different addresses and their type is also different.
The type of test2 is char *.
The type of &test2 is char **.
x = &test2
*x = test2
(*x)[0] = test2[0]
The output (memory address) of test, &test and &test[0] is numerically same but their type is different.
The type of test is char [256].
The type of &test is char (*) [256].
The type of &test[0] is char *.
As the output shows &test is same as &test[0].
x = &test[0]
*x = test[0] //first element of test array which is 'B'
(*x)[0] = ('B')[0] // Not a valid statement
Hence you are getting segmentation fault.
You cannot access a pointer to a pointer because &test is not a pointer—it's an array.
If you take the address of an array, cast the array and the address of the array to (void *), and compare them, they will (barring possible pointer pedantry) be equivalent.
What you're really doing is similar to this (again, barring strict aliasing):
putchar(**(char **)test);
which is quite obviously wrong.
Your code expects the argument x of printchar to point to memory that contains a (char *).
In the first call, it points to the storage used for test2 and is thus indeed a value that points to a (char *), the latter pointing to the allocated memory.
In the second call, however, there is no place where any such (char *) value might be stored and so it is impossible to point to such memory. The cast to (char **) you added would have removed a compilation error (about converting (char *) to (char **)) but it would not make storage appear out of thin air to contain a (char *) initialized to point to the first characters of test. Pointer casting in C does not change the actual value of the pointer.
In order to get what you want, you have to do it explicitly:
char *tempptr = &temp;
printchar(&tempptr);
I assume your example is a distillation of a much larger piece of code; as an example, perhaps you want printchar to increment the (char *) value that the passed x value points to so that on the next call the next character is printed. If that isn't the case, why don't you just pass a (char *) pointing to the character to be printed, or even just pass the character itself?
Apparently, taking the address of test is the same as taking the address of test[0]:
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("[printchar] Address of pointer to pointer: %p\n", (void *)x);
printf("[printchar] Address of pointer: %p\n", (void *)*x);
printf("Test: %c\n", **x);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
printf("[main] Address of test: %p\n", (void *)test);
printf("[main] Address of the address of test: %p\n", (void *)&test);
printf("[main] Address of test2: %p\n", (void *)test2);
printf("[main] Address of the address of test2: %p\n", (void *)&test2);
test[0] = 'B';
test2[0] = 'A';
printchar(&test2); // works
printchar(&test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Compile that and run:
forcebru$ clang test.c -Wall && ./a.out
test.c:25:15: warning: incompatible pointer types passing 'char (*)[256]' to
parameter of type 'char **' [-Wincompatible-pointer-types]
printchar(&test); // crashes because *x in printchar() has an inva...
^~~~~
test.c:4:30: note: passing argument to parameter 'x' here
static void printchar(char **x)
^
1 warning generated.
[main] Address of test: 0x7ffeeed039c0
[main] Address of the address of test: 0x7ffeeed039c0 [THIS IS A PROBLEM]
[main] Address of test2: 0x7fbe20c02aa0
[main] Address of the address of test2: 0x7ffeeed039a8
[printchar] Address of pointer to pointer: 0x7ffeeed039a8
[printchar] Address of pointer: 0x7fbe20c02aa0
Test: A
[printchar] Address of pointer to pointer: 0x7ffeeed039c0
[printchar] Address of pointer: 0x42 [THIS IS THE ASCII CODE OF 'B' in test[0] = 'B';]
Segmentation fault: 11
So the ultimate cause of the segmentation fault is that this program will try to dereference the absolute address 0x42 (also known as 'B'), which your program doesn't have permission to read.
Although with a different compiler/machine the addresses will be different: Try it online!, but you'll still get this, for some reason:
[main] Address of test: 0x7ffd4891b080
[main] Address of the address of test: 0x7ffd4891b080 [SAME ADDRESS!]
But the address that causes the segmentation fault may very well be different:
[printchar] Address of pointer to pointer: 0x7ffd4891b080
[printchar] Address of pointer: 0x9c000000942 [WAS 0x42 IN MY CASE]
The representation of char [256] is implementation dependent. It is must not be the same as char *.
Casting &test of type char (*)[256] to char ** yields undefined behavior.
With some compilers, it may do what you expect, an on others not.
EDIT:
After testing with gcc 9.2.1, it appears that printchar((char**)&test) passes in fact test as value cast to char**. It is as if the instruction was printchar((char**)test). In the printchar function, x is a pointer to the first char of the array test, not a double pointer to the first character. A double de-reference x result in a segmentation fault because the 8 first bytes of the array do not correspond to a valid address.
I get the exact same behavior and result when compiling the program with clang 9.0.0-2.
This may be considered as a compiler bug, or the result of an undefined behavior whose result might be compiler specific.
Another unexpected behavior is that the code
void printchar2(char (*x)[256]) {
printf("px: %p\n", *x);
printf("x: %p\n", x);
printf("c: %c\n", **x);
}
The output is
px: 0x7ffd92627370
x: 0x7ffd92627370
c: A
The weird behavior is that x and *x have the same value.
This is a compiler thing. I doubt that this is defined by the language.

How do I loop over a char pointer in C?

I am trying to access all elements of this preinitialized char pointer in 'c'. Here is the code:
#include <stdio.h>
#include <stdlib.h>
void main()
{
char **s="Hello";
printf("%c",*(*&s+1));
}
This code should output "e", but doesn't. What am I doing wrong?
Also, how do I access all elements one by one?
The type of s is incorrect. The string constant "Hello" has array type which can decay to type char * but you're assigning it to a variable of type char **.
Change the type of s to char * and your code will output "e":
char *s = "Hello";
Also, looking at this:
*(*&s+1)
When * comes right before & they cancel each other out. So you can simplify this to:
*(s+1)
Or equivalently:
s[1]
Assumed that you are not seeing the 'e' of the Hello, I highly recommend watching this post.
What to do when the pointer doesn't print the string properly
Just to summarize, when you reference the pointer s, it is only reading the H of Hello (since that is how the pointer of string works - it points to the first character of the string, like s[0]), and that results your code in printing out H only.
Most importantly, your pointer is double-pointer, which is incorrect.
Try it in this way.
#include <stdio.h>
#include <stdlib.h>
void main()
{
char s[] = "Hello";
printf("%s\n",s);
}

Conflicting point between char array and char pointer with returning the adress

Purpose : My main purpose was to create a string in some kind of function , it should return an adress , by returning adress using the string in main.
But I learned char array and char pointer actually using for the same purpose.
If we suppose that's true , We have these declaration :
char *arr and char arr[10] , *(arr+9)=arr[10] isn't it?
Application 1 does not work.
Application 2 does work fine.
Application 1:
#include <stdio.h>
char *foo(char arr[]);
int main(void)
{
char example[10];
example=foo(example);
printf("%s\n",example);
return 0;
}
char *foo(char arr[])
{
arr[10]="attempt";
return arr;
}
Application 2:
#include <stdio.h>
char *foo(char*);
int main(void)
{
char *example;
example=foo(example);
printf("%s\n",example);
return 0;
}
char *foo(char* arr)
{
arr="attempt";
return arr;
}
Your code will invoke undefined behavior in both segments. ( Even though you have observed that Code 2 works, it only seems to work. In reality a failure is lurking, and can show without warning. )
Make these corrections to address that problem, and see comments for explanations:
In code 1:
//int main(void){
int main(void){//int main(void) is minimum prototype for main function.
//char example[10]; // this will invoke undefined behavior
char example[10] = {"something"}; // 'example' initialized with content,
// thus averting undefined behavior
//example=foo(example);
strcpy (example, foo(example)); // char array is not assignable using `=`
// use strcpy to transfer result of "foo"
printf("%s\n",example);
return 0;
}
char *foo(char arr[]) //note: char arr[] decays into char *arr
{
//char arr[10]="attempt"; // Error: redefinition of 'arr' with a
// different type: char[10] vs char *
arr = "attempt"; //because char [] decays into char *, 'arr' is usable as is.
return arr;
}
To answer your question in comments: Why using strcpy function [after variable example was initialized] is not a undefined behaviour.
First the definition of a C string is important to know. ( C string definition is found here. )
The variable example in its original form, i.e. initialized:
char example[10];
Can contain anything. For example:
|%|h|8|\#|d|o|-|~|*|U|?|?|?|?|
// ^end of memory for 'example`
// note that the character in example[9] == 'U', not NULL, therefore, not a C string.
This would cause the function strcpy() to fail. Initializing guarantees predictable results:
char example[10] = {"something"};//properly initialized
|s|o|m|e|t|h|i|n|g|0|?|?|?|?|
// ^end of memory for 'example`
//or
char example[10] = {0}; //also properly initialized
|0|0|0|0|0|0|0|0|0|0|?|?|?|?|
// ^end of memory for 'example`
(This would require an extra step to place proper content.):
strcpy(example, "something");
The only required adjustment to Code 2 is to initialize the pointer before using: (See the reason why pointer must be initialized here.)
char *foo(char*);
//int main(void){
int main(void){//int main(void) is minimum prototype for main function.
{
//char *example; // passing this will envoke undefined behavior
char *example = NULL;// must initialize before using
example=foo(example);
printf("%s\n",example);
return 0;
}
char *foo(char* arr)
{
arr="attempt";
return arr;
}
Both do not "work" for different reasons.
The first is undefined behavior (UB) as code attempts to assign an element outside the bounds of example[10].
arr[0]='\0'; or arr[9]='\0'; would have been OK given the value passed to foo().
Converting the address of the string literal "attempt" to a char is not good code either. A well enabled compiler will warn of this basic coding lapse. #f3rmat example
char *foo(char arr[]) {
arr[10]="attempt"; <-- UB
return arr;
}
char example[10];
example=foo(example);
The 2nd is UB because code attempted to use an uninitialized value in passing a pointer. This "works" in that the UB of passing an uninitialized pointer is often benign. Since foo() does not use this "garbage" value and the rest of good is well defined, it "works".
char *foo(char* arr) {
arr="attempt";
return arr;
}
char *example;
example=foo(example); // UB - likely a garbage value is passed to `foo()`.
printf("%s\n",example); // `example` is now pointing to `"attempt"`.
I learned char array and char pointer actually using the same purpose.
Pointers and arrays are related, yet different. Avoid the "actually using the same purpose" idea.
An array is like a row of houses on a street. A pointer is the address of a house written on a piece of paper in your hand. Houses ≠ scrap of paper. You can refer to the house by its address or even a row of houses by the first house's address, yet a house and its address are different.
I tried to compile Code '1' and got the following error:
prog.c: In function ‘main’:
prog.c:8:12: error: assignment to expression with array type
example=foo(example);
prog.c: In function ‘foo’:
prog.c:14:12: warning: assignment makes integer from pointer without a cast [-
Wint-conversion]
arr[10]="attempt\n";
^
You get error: assignment to expression with array type example=foo(example); because in your left hand side, you're using an array type, which is not assignable. Assignment operator (=) needs to have a modifiable lvalue as its left operand.
You get a warning: assignment makes integer from pointer without a cast [Wint-conversion] arr[10]="attempt\n"; because the left hand side and the right hand side in this assignment have different types.
Pointer and array are not the same.
char *arr = "attempt"
Here you're creating a string constant "attempt" and assigning its address to arr which is valid
char arr[10];
arr = "attempt";
This is invalid.
you can add elements to the array by following methods.
char arr[10] = "attempt";
char arr[10] = {'a', 't', 't', 'e', 'm', 'p', 't'};
arr[0] = 'a';
arr[1] = 't'; // and so on.
when you are passing the array as an argument to another function
arr = foo(arr);
you are passing the address of the zeroth element in the array arr[0]
Hope that helps..
Char arrays can be initialized but cannot be assigned.
char example[10]="attempt";
is valid.
But
char example[10];
example="attempt"
is not valid.
More details here
Your second example works because you pass a uninitialized pointer to a function and return an address of the string literal attempt
which will work perfectly as mentioned in the answer by chux

Resources