Using double pointers in C - c

Am doing a task where am supposed to used getline function read input from a user from the terminal. Here is my code:
int main(int ac, char **av)
{
printf("Write something: \n");
char **buf = NULL;
size_t buf_size = 0;
ssize_t bytes_read = getline(buf, &buf_size, stdin);
if (bytes_read != -1)
write(STDOUT_FILENO, buf, buf_size);
else
printf("An error occured\n");
free(buf);
return (0);
}
From the code above. My program displayed the text: An error occurred.
Did some code refactoring and this is what I came up with:
int main(int ac, char **av)
{
printf("Write something: \n");
char *buf = NULL;
size_t buf_size = 0;
ssize_t bytes_read = getline(&buf, &buf_size, stdin);
if (bytes_read != -1)
write(STDOUT_FILENO, buf, buf_size);
else
printf("An error occured\n");
free(buf);
return (0);
}
Voila! The code displayed whatever was inputted, just what I wanted. So I fixed my the issue. But what am trying to understand is what's wrong the first code snippet? An it is right to do this?:
char **name = "John Doe";
or
char **name = NULL;
I did some quick test on an online compiler. Here is the code:
int main() {
// Write C code here
char **name = "John Doe";
printf("%p\n", name); //0x55f5f9890004
printf("%p\n", *name); //0x656f44206e686f4a
printf("%c\n", *name); //J
printf("%p", "John Doe"); //0x55f5f9890004
return 0;
}
I realised that the double pointer was just treated as a single char pointer. Not sure if my finding are right. If you can give a better explanation the above main function that would be cool.

When you want to change a variable in a function you need to pass it by reference. Otherwise the function will deal with a copy of the value of the original object used as an argument expression and changing the copy of the value will not influence on the value of the original object.
In C passing by reference means passing an object indirectly through a pointer to it.
Thus dereferencing the pointer the function will have a direct access to the original object and can change it.
In this code snippet
char *buf = NULL;
size_t buf_size = 0;
ssize_t bytes_read = getline(&buf, &buf_size, stdin);
you want that the pointer buf after calling the function getline would point to a string read in the function. So you need to pass it to the function by reference the same way as you are passing another variable buf_size the value of which is also changed within the function and the caller of the function needs to know the result value of the variable.
If you will write
char **buf = NULL;
size_t buf_size = 0;
ssize_t bytes_read = getline(buf, &buf_size, stdin);
then the function within itself will try to dereference the null pointer buf that results in undefined behavior because it thinks that the so-called "double pointer" points to an object of the type char * that the function needs to change.
To make it more clear consider the following demonstration programs.
#include <stdio.h>
void f( char *s )
{
s = "World!";
}
int main( void )
{
char *s = "Hello";
printf( "Before calling f s = %s\n", s );
f( s );
printf( "After calling f s = %s\n", s );
}
The program output is
Before calling f s = Hello
After calling f s = Hello
The pointer s passed to the function be value. That is the function deals with a copy of the value of the pointer. Changing the copy does not influence on the original value of the pointer s.
Now consider the next program
#include <stdio.h>
void f( char **s )
{
*s = "World!";
}
int main( void )
{
char *s = "Hello";
printf( "Before calling f s = %s\n", s );
f( &s );
printf( "After calling f s = %s\n", s );
}
The program output is
Before calling f s = Hello
After calling f s = World!
That is as the pointer s is passed to the function by reference the function can change the original pointer s by dereferencing the pointer passed to the function that points to the original pointer s.
As for this declaration
char **name = "John Doe";
then the compiler should issue a message that declaration is wrong. The string literal used as an initializer is implicitly converted tp pointer to its first element of the type char *. But the initialized variable has the type char ** and there is no implicit conversion between these pointer types.
Also the conversion specifier %s expects an argument of the type char * instead of the type char **.
So you have to write
char *name = "John Doe";
Or as you may not change a string literal then it will be better to write the declaration like
const char *name = "John Doe";

In the char *buf case, getline will go to the memory location of the pointer buf and change that address.
In case of char **buf = NULL;, getline will go the memory location "null" and try to change that address, which is nonsense. You essentially lie to getline and tell it that you stored a pointer for it at memory location "null".
As for char **name = "John Doe"; it is a constraint violation of C's assignment rules, anything can happen since the code isn't valid C. Including "seems to work fine all the way until the mysterious crash some years later in live production code". You might want to take the skunk out of that online compiler by for example applying What compiler options are recommended for beginners learning C?

A double pointer has to reference a valid pointer to work (as that pointer will store the reference to the newly allocated memory.
int main(int ac, char **av)
{
printf("Write something: \n");
char *realBuf = NULL
char **buf = &realBuf;
size_t buf_size = 0;
ssize_t bytes_read = getline(buf, &buf_size, stdin);
if (bytes_read != -1)
write(STDOUT_FILENO, *buf, buf_size);
else
printf("An error occured\n");
free(*buf);
return (0);
}

There are no “double pointers” in C, so you cannot use them.
But for any type T, you can create a type “pointer to T”. And that’s the case if T is a pointer type as well. That’s a pointer to a pointer. Not a “double pointer”. If you see char** as a “double pointer” you will forever be confused.

Related

function returns address of local variable [-Wreturn-local-addr] sprintf

i ma new c and i am trying sprintf along with pointers. all i get in console is return buf; as is please help me with this code.
#include <stdio.h>
char* stringa(char* str);
int main()
{
char* ss = "123";
stringa(ss);
return 0;
}
char* stringa( char* str)
{
char buf [100] ;
sprintf(buf,"hello %s", str);
return buf;
}
i tried many other ways too like sprintf_c and my computer shut down for serious. i am learning c.
Maybe this is what you want
#include <stdio.h>
char* stringa(char* dest, char* src)
int main()
{
char buf [100] ;
char* ss = "123";
printf("%s\n", stringa(buf, ss));
return 0;
}
char* stringa(char* dest, char* src)
{
sprintf(dest,"hello %s", src);
return dest;
}
In function 'char* stringa(char* str)' you are not allocating space in the heep for the char array 'buf' you are allocating space on the stack for that variable. (meaning after the function finishes, the variable 'buf' will be wiped away because it will be out of scope) therefore you must ask the compiler to allocate space in memory for this array, I recommend using malloc()
ex:
char* stringa( char* str)
{
char *buf = (char*)malloc(sizeof(char) * 100);
sprintf(buf,"hello %s", str);
return buf;
}
char* stringa( char* str)
{
char buf [100] ;
sprintf(buf,"hello %s", str);
return buf;
}
The problem with this code is that the buf char array is local to the stringa function. When the function returns, the memory occupied by the buf array is not valid anymore (for example, it could be reused later to store the content of other variables, arrays, etc.).
So when the function returns, you are giving the caller a pointer to garbage memory, to invalid data. The C compiler is trying to help you with that warning message; it's telling you: "Sorry, you are trying to pass back to the caller the address of a local variable (i.e. the buf char array) that is not valid anymore when the function terminates."
To fix this problem one option could be to allocate the char array for the output string at the call site, and let the invoked stringa function write into the caller-provided array:
#include <stdio.h>
char* stringa(char* dest, const char* str);
int main()
{
const char* ss = "123";
char buf[100];
stringa(buf, ss);
return 0;
}
/* Write the final message into 'dest'.
* Return the same dest address.
*/
char* stringa(char* dest, const char* str)
{
/* Note: better using a safe string function
* to prevent buffer overflows (e.g. sprintf_s),
* passing the maximum destination array size as well.
*/
sprintf(dest,"hello %s", str);
return dest;
}
Note that I also added some consts in your code to enforce some const-correctness for read-only input strings.

Adding to an array in main via function argument

I'm not sure if I even worded the title correctly, but basically. I want to know if there is a way to add to the buff array from the hey function using the pointers in the arguments and why does it work if it does?
buf[100].
example:
int main(){
char buf[100];
hey("320244",buf);
printf("%s", buf);
}
void hey(char* s, char* result){
/*
some code that appends to result using pointers
do some stuff with s and get the result back in buf without using return.
*/
}
I have modified your code with some comments :-
#define LEN 100 //Use a macro instead of error prone digits in code
void hey(char* s, char* result); //Fwd declaration
int main(){
char buf[LEN] = {0}; //This will initialize the buffer on stack
hey("320244",buf);
printf("%s", buf);
hey("abc", buf); //Possible future invocation
printf("%s", buf);
}
void hey(char* s, char* result){
if(strlen(result) + strlen(s) < LEN ) //This will check buffer overflow
strcat(result, s); //This will concatenate s into result
else
//Do some error handling here
}
Let's do the right thing, and use a structure to describe a dynamically allocated, grow-as-needed string:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct mystring {
char *ptr; /* The actual string */
size_t len; /* The length of the string */
size_t max; /* Maximum number of chars allocated for */
};
#define MYSTRING_INIT { NULL, 0, 0 }
If we want to append something to a struct mystring, we define a function that takes a pointer to the structure the function can modify. (If it only needed a char pointer instead of a structure, it'd take a char **; a pointer to a char pointer.)
void mystring_append(struct mystring *ms, const char *s)
{
const size_t slen = (s) ? strlen(s) : 0;
/* Make sure ms points to a struct mystring; is not NULL */
if (!ms) {
fprintf(stderr, "mystring_append(): No struct mystring specified; ms == NULL!\n");
exit(EXIT_FAILURE);
}
/* Make sure we have enough memory allocated for the data */
if (ms->len + slen >= ms->max) {
const size_t max = ms->len + slen + 1;
char *ptr;
ptr = realloc(ms->ptr, max);
if (!ptr) {
fprintf(stderr, "mystring_append(): Out of memory!\n");
exit(EXIT_FAILURE);
}
ms->max = max;
ms->ptr = ptr;
}
/* Append. */
if (slen > 0) {
memmove(ms->ptr + ms->len, s, slen);
ms->len += slen;
}
/* We allocated one char extra for the
string-terminating nul byte, '\0'. */
ms->ptr[ms->len] = '\0';
/* Done! */
}
The (s) ? strlen(s) : 0; expression uses the ?: conditional operator. Essentially, if s is non-NULL, the expression evaluates to strlen(s), otherwise it evaluates to 0. You could use
size_t slen;
if (s != NULL)
slen = strlen(s);
else
slen = 0;
instead; I just like the concise const size_t slen = (s) ? strlen(s) : 0 form better. (The const tells the compiler that the slen variable is not going to be modified. While it might help the compiler generate better code, it is mostly a hint to other programmers that slen will have this particular value all through this function, so they do not need to check if it might be modified somewhere. It helps code maintenance in the long term, so it is a very good habit to get into.)
Normally, functions return success or error. For ease of use, mystring_append() does not return anything. If there is an error, it prints an error message to standard output, and stops the program.
It is a good practice to create a function that releases any dynamic memory used by such a structure. For example,
void mystring_free(struct mystring *ms)
{
if (ms) {
free(ms->ptr);
ms->ptr = NULL;
ms->len = 0;
ms->max = 0;
}
}
Often, you see initialization functions as well, like
void mystring_init(struct mystring *ms)
{
ms->ptr = NULL;
ms->len = 0;
ms->max = 0;
}
but I prefer initialization macros like MYSTRING_INIT, defined earlier.
You can use the above in a program like this:
int main(void)
{
struct mystring message = MYSTRING_INIT;
mystring_append(&message, "Hello, ");
mystring_append(&message, "world!");
printf("message = '%s'.\n", message.ptr);
mystring_free(&message);
return EXIT_SUCCESS;
}
Notes:
When we declare a variable of the structure type (and not as a pointer to the structure, i.e. no *), we use . between the variable name and the field name. In main(), we have struct mystring message;, so we use message.ptr to refer to the char pointer in the message structure.
When we declare a variable as a pointer to a structure type (as in the functions, with * before the variable name), we use -> between the variable name and the field name. For example, in mystring_append() we have struct mystring *ms, so we use ms->ptr to refer to the char pointer in the structure pointed to by the ms variable.
Dynamic memory management is not difficult. realloc(NULL, size) is equivalent to malloc(size), and free(NULL) is safe (does nothing).
In the above function, we just need to keep track of both current length, and the number of chars allocated for the dynamic buffer pointed to by field ptr, and remember that a string needs that terminating nul byte, '\0', which is not counted in its length.
The above function reallocates only just enough memory for the additional string. In practice, extra memory is often allocated, so that the number of reallocations needed is kept to a minimum. (This is because memory allocation/reallocation functions are considered expensive, or slow, compared to other operations.) That is a topic for another occasion, though.
If we want a function to be able to modify a variable (be that any type, even a structure) in the callers scope -- struct mystring message; in main() in the above example --, the function needs to take a pointer to variable of that type, and modify the value via the pointer.
The address-of operator, &, takes the address of some variable. In particular, &message in the above example evaluates to a pointer to a struct mystring.
If we write struct mystring *ref = &message;, with struct mystring message;, then message is a variable of struct mystring type, and ref is a pointer to message; ref being of struct mystring * type.
If I have understood you correctly you mean the following
#include <string.h>
//...
void hey(char* s, char* result)
{
strcpy( result, s );
}
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
void hey( const char* s, char* result);
int main(void)
{
char buf[100];
hey( "320244", buf );
printf( "%s\n", buf );
return 0;
}
void hey( const char* s, char* result )
{
strcpy( result, s );
}
Its output is
320244
If the array buf already stores a string then you can append to it a new string. For example
#include <string.h>
//...
char buf[100] = "ABC";
strcat( buf, "320244" );
Take into account that the function hey should be declared before its usage and according to the C Standard the function main shall be declared like
int main( void )

Proper way to return a string in C

I have the following code:
char* get_address_string(PACKAGE* pkg){
char *c;
sprintf(c, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1],
pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return c;
}
The code works fine. However, I know this is not the proper way to return a string in C. I am receiving the warning "c is used uninitialized in this function".
What is the proper way to write this function in C?
"Proper way to return a string in C" is not truly possible. In C, a string is a character array (up to and including the null character) and arrays, by themselves, cannot be returned from a function.
A function can return pointers. So the usual method of "return a string" it to:
Return a pointer. char *foo1(...) like char *strdup()
Pass in a pointer to a character array and modify its contents. void foo2(char *,...) like int sprintf(char *dest, const char *format, ...)
Combine 1 & 2 char *foo3(char *, ...) like char *strcpy(char *dest, char *src)
Pass the address of a pointer and update that. foo4(char **ptr) like ssize_t getline(char **lineptr, size_t *n, FILE *stream)
The key is that the memory associated with the pointer must be valid after the function is complete. Returning a pointer to a function's non-static memory is undefined behavior. Successful methods include having the calling code pass in the pointer, or the function providing it via memory allocation of pointer to some persistent value like a global variable or string constant.
What is the proper way to write this function in C?
Current design practice encourages functions like #2 & #3 above to also supply a size_t size so the function knowns the limitations of the memory available.
char *foo2(char *s, size_t size, const pkg_T *pkg) {
int result = snprintf(s, size, "%02x:%02x:%02x:%02x:%02x:%02x",
pkg->address[0], pkg->address[1], pkg->address[2],
pkg->address[3], pkg->address[4], pkg->address[5]);
// encoding error or not enough room
if (result < 0 || result >= size) return NULL;
return s;
}
Another method would allocate memory (I favor the above though). This obliges the calling code to free() the memory.
#define UINT_MAX_WIDTH (sizeof(unsigned)*CHAR_BIT/3 + 3)
char *foo2alloc(char *s, size_t size, const pkg_T *pkg) {
char buf[(UINT_MAX_WIDTH+3)*6 + 1];
int result = snprintf(buf, sizeof buf, "%02x:%02x:%02x:%02x:%02x:%02x",
pkg->address[0], pkg->address[1], pkg->address[2],
pkg->address[3], pkg->address[4], pkg->address[5]);
// encoding error or not enough room
if (result < 0 || result >= size) return NULL;
return strdup(buf);
}
c is a pointer, but no memory is allocated. The return value is ok, that's how it can be done in C.
But you need to allocate memory.
Since c is uninitialized, sprintf writes to an unknown memory location, which leads to unspecified behavior. It might crash immediately, it might not crash at all, or it might crash on some completely unrelated line of code.
You need to initialize the pointer by allocating memory to it with malloc.
char* get_address_string(PACKAGE* pkg){
char *c = malloc(20); // enough room for output as 00:11:22:33:44:55 plus null terminator
if (c == null) {
perror("malloc failed");
exit(1);
}
sprintf(c, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1], pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return c;
}
Note that even though you know ahead of time how much memory you need, you can't set it aside at compile time via an array. This is wrong:
char* get_address_string(PACKAGE* pkg){
char c[20]; // allocated on the stack, contents unspecified on return
sprintf(c, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1], pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return c;
}
As is this:
char* get_address_string(PACKAGE* pkg){
char c[20]; // allocated on the stack, contents unspecified on return
char *p = c;
sprintf(p, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1], pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return p;
}
Since c is allocated on the stack, when get_address_string returns the contents are unspecified, leading again to unspecified behavior.
I prefer allocating heap from the caller so that it's clear who should free it.
#include <stdio.h>
#include <malloc.h>
bool GetString(char ** retString, size_t size)
{
// use size to do range check
sprintf_s(*retString, size, "blah blah blah");
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
size_t size = 100;
char *data = (char *)malloc(size);
if (data)
{
GetString(&data, size);
free(data);
}
return 0;
}

C - proper syntax for pointer

I call a function global var as follow:
char *Pointer;
I then pass it into function:
char *MyChar = DoSomething (&Pointer);
which is defined as:
char *DoSomething (char *Destination)
{
free (*Destination);
//re-allocate memory
Destination = malloc (some number);
//then do something...
//finally
return Destination;
}
it only works if I use (*Destination) instead of (Destination). can someone tell me if that is correct? I still do not understand why it does not take (Destination).
It is correct, Destination is already declared as a pointer, so you pass the address of Destination in DoSomething(&Destination), that is like a pointer to pointer, then you need to dereference Destination inside DoSomething() function, for which the indirection operator * works.
But the right way, is not to pass the address of the pointer, but the pointer instead like in
DoSomething(Destination);
now, since you want to malloc Destination inside the function, you should the do this
char * DoSomething( char **Destination )
{
// free( Destination ); why?
//re-allocate memory
*Destination = malloc( some number );
//then do something...
//finally
return *Destination;
}
this is a demonstration of how you can use pointers
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *copyString(const char *const source)
{
char *result;
int length;
length = strlen(source);
result = malloc(length + 1);
if (result == NULL)
return NULL;
strcpy(result, source);
printf("The address of result is : %p\n", result);
printf("The content of result is : %s\n", result);
printf("The first character of result is # %p\n", &result[0]);
return result;
}
int main()
{
char *string = copyString("This is an example");
printf("\n");
printf("The address of string is : %p\n", string);
printf("The content of string is : %s\n", string);
printf("The first character of string is # %p\n", &string[0]);
/* we used string for the previous demonstration, now we can free it */
free(string);
return 0;
}
if you execute the previous program, you will see that the pointers both point to the same memory, and the contents of the memory are the same, so calling free in main() will realease the memory.
Here is a correct approach
char *Pointer;
//,,, maybe allocating memory and assigning its address to Pointer
//... though it is not necessary because it is a global variable and
//... will be initialized by zero. So you may apply function free to the pointer.
char *MyChar = DoSomething( Pointer );
char * DoSomething( char *Destination )
{
free( Destination );
//re-allocate memory
Destination = malloc( some number );
//then do something...
//finally
return Destination;
}
As for your code then
Type of the argument does not correspond to type of the parameter in function call
char *MyChar = DoSomething (&Pointer);
the type of the parameter is char * ( char *Destination ) while the type of argument is
char ** ( &Pointer )
As Destination is a pointer then instead of
free (*Destination);
you have to write
free( Destination );
It's because you are passing in an address of the pointer char *Pointer with the line
char *MyChar = DoSomething (&Pointer);
Since you are passing in the address of the pointer in your function DoSomething it sees the functional scope variable Destination as a pointer to an address that is the address of the pointer Pointer.
So rather than passing in the address of Pointer with
char *MyChar = DoSomething(&Pointer);
you need to pass in the pointer itself like so:
char *MyChar = DoSomething(Pointer);
which will allow you to use
free(Destination);
Notice the lack of & indicating the address of Pointer.

How to Return an Array of Strings in C?

For example, I have in the main file
1) char ** array[NUMBER];
2) array = build_array();
and in an imported file
char ** build_array()
{
char ** array[NUMBER];
strings[0] = "A";
strings[1] = "B";
return (char *) strings;
}
However, at line 2 in the main file, I get the error: "incompatible types when assigning to type 'char **[(unsighed int)NUMBER]' from type 'char **'
What am I doing wrong? Any suggestions or advice would be appreciated. Thank you in advance.
There seem to be some confusion about what a string is in C. In C, a null terminated sequence of chars is considered a string. It is usually represented by char*.
I just want to call the build_array() function and return the array of strings
You pretty much can't return an array, neither a pointer to a local array. You could however pass the array to build_array as an argument, as well as its size, and fill that instead.
void build_array( char* strings[], size_t size )
{
// make sure size >= 2 here, based on your actual logic
strings[0] = "A";
strings[1] = "B";
}
...later called as:...
char *array[NUMBER];
build_array(array, NUMBER);
The alternatives are to return a pointer to a global or static allocated array, which would make your function non-reentrant. You probably don't care about this now, but is bad practice so I would recommend you avoid going that route.
As littleadv pointed out, there are several problems with your code:
Mismatch between char ** and char **[ ]
Returning a pointer to a local variable
Etc.
This example might help:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define NUMBER 2
#define MAX_STRING 80
char **
build_array ()
{
int i = 0;
char **array = malloc (sizeof (char *) * NUMBER);
if (!array)
return NULL;
for (i = 0; i < NUMBER; i++) {
array[i] = malloc (MAX_STRING + 1);
if (!array[i]) {
free (array);
return NULL;
}
}
strncpy (array[0], "ABC", MAX_STRING);
strncpy (array[1], "123", MAX_STRING);
return array;
}
int
main (int argc, char *argv[])
{
char **my_array = build_array ();
if (!my_array) {
printf ("ERROR: Unable to allocate my_array!\n");
return 1;
}
else {
printf ("my_array[0]=%s, my_array[1]=%s.\n",
my_array[0], my_array[1]);
}
return 0;
}
Your return type is char**, while you're assigning it to char**[], that's incompatible.
Other than that you should post the actual code that you have problem with, the code you posted doesn't compile and doesn't make much sense.
In order to fix your code, the function should be returning char **[NUMBER]. Note also, that you're casting the return value to char* instead of char** that you declared (or char **[NUMBER] that it should be, and in fact - is).
Oh, and returning a pointer to a local variable, as you do in your case, is a perfect recipe for crashes and undefined behavior.
What you probably meant was:
char *array[NUMBER];
int ret = build_array(array, NUMBER);
// do something with return value or ignore it
and in an imported file
int build_array(char **arr, int size)
{
// check that the size is large enough, and that the
// arr pointer is not null, use the return value to
// signal errors
arr[0] = "A";
arr[1] = "B";
return 0; // asume 0 is OK, use enums or defines for that
}

Resources