pointers to pointers and pointer arrays - c

gcc 4.4.4 c89
I understand pointers ok. However, I am stepping up to pointer arrays and pointers to pointers.
I have been messing around with this code snippet and have left comments of what I think I understand.
Many thanks for any advice if my comments are correct with the line of code?
void increment_ptr()
{
/* Static char array */
char src[] = "rabbit";
/* pointer to array of pointers to char's - create 6 pointers in this array */
char *dest[sizeof(src)];
size_t i = 0;
/* pointer to a char */
char* chr_ptr = NULL;
/* pointer to pointer that points to a char */
char** ptr_ptr = NULL;
/* chr_ptr pointer now points to the memory location where 'rabbit' is stored. */
chr_ptr = src;
/* ptr_ptr points to the first memory address of the pointer array of where dest is stored */
ptr_ptr = dest;
/* Deference chr_ptr and keep going until nul is reached 'rabbit\0' */
while(*chr_ptr != '\0')
/* deference ptr_ptr and assign the address of each letter to the momory location where
ptr_ptr is currently pointing to. */
*ptr_ptr++ = chr_ptr++;
/* reset the ptr_ptr to point to the first memory location 'rabbit' */
ptr_ptr = dest;
/* Keep going until NULL is found - However, my program never finds it, ends in UB */
while(ptr_ptr != NULL) {
/* Dereference what the pointer to pointer is pointing at the memory lcoation */
printf("[ %s ]\n", *ptr_ptr++);
}
}

Comments below each part (bits I haven't mentioned are correct):
/* Static char array */
char src[] = "rabbit";
This array is not static - it has auto storage duration.
/* pointer to array of pointers to char's - create 6 pointers in this array */
char *dest[sizeof(src)];
This is an array of pointers to char, not a pointer to an array. The length of the array is 7, because the sizeof(src) is 7 (it includes the nul string terminator).
/* chr_ptr pointer now points to the memory location where 'rabbit' is stored. */
chr_ptr = src;
More precisely, it points at the first character in src, which is the 'r' in "rabbit".
/* ptr_ptr points to the first memory address of the pointer array of where dest is stored */
ptr_ptr = dest;
It points at the first pointer in the dest array.
/* Keep going until NULL is found - However, my program never finds it, ends in UB */
while(ptr_ptr != NULL) {
Correct - because you never initialised dest. You could change the declaration of dest to this:
char *dest[sizeof(src)] = { 0 };
...and it will work.

I would suggest that you read Section 6 of the online C-FAQ: 6. Arrays and Pointers

The error is when you assign dest to ptr_ptr, which is actually an uninitialized array of pointers to chars, going through it withing the while loop will fail.
/* reset the ptr_ptr to point to the first memory location 'rabbit' */
ptr_ptr = dest;
/* Keep going until NULL is found - However, my program never finds it, ends in UB */
while(ptr_ptr != NULL) {
/* Dereference what the pointer to pointer is pointing at the memory lcoation */
printf("[ %s ]\n", *ptr_ptr++);
}

Related

Differences between allocating memory spaces for a string based on the size of its characters vs. the size of the entire string

When we allocating memory spaces for a string, do the following 2 ways give the same result?
char *s = "abc";
char *st1 = (char *)malloc(sizeof(char)*strlen(s));
char *st2 = (char *)malloc(sizeof(s));
In other words, does allocate the memory based on the size of its characters give the same result as allocating based on the size of the whole string?
If I do use the later method, is it still possible for me to add to that memory spaces character by character such as:
*st = 'a';
st++;
*st = 'b';
or do I have to add a whole string at once now?
Let's see if we can't get you straightened out on your question and on allocating (and reallocating) storage. To begin, when you declare:
char *s = "abc";
You have declared a pointer to char s and you have assigned the starting address for the String Literal "abc" to the pointer s. Whenever you attempt to use sizeof() on a_pointer, you get sizeof(a_pointer) which is typically 8-bytes on x86_64 (or 4-bytes on x86, etc..)
If you take sizeof("abc"); you are taking the size of a character array with size 4 (e.g. {'a', 'b', 'c', '\0'}), because a string literal is an array of char initialized to hold the string "abc" (including the nul-terminating character). Also note, that on virtually all systems, a string literal is created in read-only memory and cannot be modified, it is immutable.
If you want to allocate storage to hold a copy of the string "abc", you must allocate strlen("abc") + 1 characters (the +1 for the nul-terminating character '\0' -- which is simply ASCII 0, see ASCII Table & Description.
Whenever you allocate memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. So if you allocate for char *st = malloc (len + 1); characters, you do not want to iterate with the pointer st (e.g. no st++). Instead, declare a second pointer, char *p = st; and you are free to iterate with p.
Also, in C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?.
If you want to add to an allocation, you use realloc() which will create a new block of memory for you and copy your existing block to it. When using realloc(), you always reallocate using a temporary pointer (e.g. don't st = realloc (st, new_size);) because if when realloc() fails, it returns NULL and if you assign that to your pointer st, you have just lost the original pointer and created a memory leak. Instead, use a temporary pointer, e.g. void *tmp = realloc (st, new_size); then validate realloc() succeeds before assigning st = tmp;
Now, reading between the lines that is where you are going with your example, the following shows how that can be done, keeping track of the amount of memory allocated and the amount of memory used. Then when used == allocated, you reallocate more memory (and remembering to ensure you have +1 bytes available for the nul-terminating character.
A short example would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define THISMANY 23
int main (void) {
char *s = "abc", *st, *p; /* string literal and pointer st */
size_t len = strlen(s), /* length of s */
allocated = len + 1, /* number of bytes in new block allocated */
used = 0; /* number of bytes in new block used */
st = malloc (allocated); /* allocate storage for copy of s */
p = st; /* pointer to allocate, preserve st */
if (!st) { /* validate EVERY allocation */
perror ("malloc-st");
return 1;
}
for (int i = 0; s[i]; i++) { /* copy s to new block of memory */
*p++ = s[i]; /* (could use strcpy) */
used++; /* advance counter */
}
*p = 0; /* nul-terminate copy */
for (size_t i = 0; i < THISMANY; i++) { /* loop THISMANY times */
if (used + 1 == allocated) { /* check if realloc needed (remember '\0') */
/* always realloc using temporary pointer */
void *tmp = realloc (st, 2 * allocated); /* realloc 2X current */
if (!tmp) { /* validate EVERY reallocation */
perror ("realloc-st");
break; /* don't exit, original st stil valid */
}
st = tmp; /* assign reallocated block to st */
allocated *= 2; /* update allocated amount */
}
*p++ = 'a' + used++; /* assign new char, increment used */
}
*p = 0; /* nul-terminate */
printf ("result st : %s\n" /* output final string, length, allocated */
"length st : %zu bytes\n"
"final size : %zu bytes\n", st, strlen(st), allocated);
free (st); /* don't forget to free what you have allocated */
}
Example Use/Output
$ ./bin/sizeofs
result st : abcdefghijklmnopqrstuvwxyz
length st : 26 bytes
final size : 32 bytes
Look things over and let me know if this answered your questions, and if not, leave a comment and I'm happy to help further.
If you are still shaky on what a pointer is, and would like more information, here are a few links that provide basic discussions of pointers that may help. Difference between char pp and (char) p? and Pointer to pointer of structs indexing out of bounds(?)... (ignore the titles, the answers discuss pointer basics)

Why char * c = NULL; causes an error in the following code?

My understanding:
char * c means c is pointing nothing.
When I type "Hello World", c is now pointing the first address of "Hello World".
It should print H and e, but I got "Segmentation fault: 11" error.
Can anyone please enlighten me why and how char * c = NULL; is causing an error?
Thanks in advance!
#include <stdio.h>
int main(void)
{
char * c = NULL;
gets(c);
printf("%c, %c\n", c[0], c[1]);
return 0;
}
gets doesn't allocate memory. Your pointer is pointing to NULL, which cannot be written to, so when gets tries to write the first character there, you seg fault.
The solution is:
Use a stack or global array (char c[1000];) or a pointer to dynamically allocated memory (char *c = malloc(1000);), not a NULL pointer.
Never use gets, which is intrinsically broken/insecure (it can't limit the read to match the size of the available buffer); use fgets instead.
char *c = NULL; declares the pointer c initialized to NULL. It is a pointer to nowhere.
Recall, A pointer is just a variable that holds the address to something else as its value. Where you normally think of a variable holding an immediate values, such as int a = 5;, a pointer would simply hold the address where 5 is stored in memory, e.g. int *b = &a;. Before you can use a pointer to cause data to be stored in memory -- the pointer must hold the address for (e.g. it must point to) the beginning of a valid block of memory that you have access to.
You can either provide that valid block of memory by assigning the address of an array to your pointer (where the pointer points to where the array is stored on the stack), or you can allocate a block of memory (using malloc, calloc or realloc) and assign the beginning address for that block to your pointer. (don't forget to free() what you allocate).
The simplest way is to declare a character array and then assign the address to the first element to your pointer (an array is converted to a pointer to the first element on access, so simply assigning the character array to your pointer is fine). For example with the array buf providing the storage and the pointer p holding the address of the first character in buf, you could do:
#include <stdio.h>
#include <string.h> /* for strcspn & strlen */
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void)
{
char buf[MAXC], /* an array of MAXC chars */
*p = buf; /* a pointer to buf */
if (fgets (p, MAXC, stdin)) { /* read line from stdin */
p[strcspn (p, "\n")] = 0; /* trim \n by overwriting with 0 */
if (strlen (p) > 1) { /* validate at least 2-chars */
printf("%c, %c\n", p[0], p[1]); /* output them */
}
}
return 0;
}
(note: strcspn above simply returns the number of character in your string up to the '\n' character allowing you to simply overwrite the '\n' included by fgets() with '\0' -- which is numerically equivalent to 0)
Example Use/Output
$ ./bin/fgetsmin
Hello
H, e
Look things over and let me know if you have further questions.

Not getting output

I was trying to scan a string input from the user and then print it in the next line, but I'm not able to figure out, as I'm new to coding, why it is showing no output! Below is the code-
main()
{
char* w1,w2,w3,e1,e2,e3;
printf("List of Words");
printf("\tMeanings");
scanf("%s",&w1);
printf("\n%s",w1);
getch();
}
I expected w1 to print under "List of Words" but it isn't showing any output.
Here
char* w1; /* uninitialized pointer */
scanf("%s",&w1); /* for w1 no memory is allocated. Also & is not required since w1 tends to points to some address */
w is character pointer and pointer needs to point to some valid memory location, but in your case w1 not having any valid memory.
Allocate memory for w first and then put the input data into w using scanf(). For e.g
#define BUF_MAX_LENGTH 10
char *w1 = malloc(BUF_MAX_LENGTH);
if(w1 == NULL) {
/* #TODO error handling */
}
And then scan the data into w1. For e.g
scanf("%s", w1);
And once usage is done with w do not forget to free the dynamically allocated memory to avoid memory leakage. For e.g
free(w1);
Side note, do avoid declaring character variable & character pointer variable in same declaration to improve code readability. For e.g
char* w1,w2,w3,e1,e2,e3; /* mixed up */
can be
char* w1 = NULL; /* All pointer declaration */
char w2,w3,e1,e2,e3; /* All normal char variable */

How do I use char** ? (pointer to an array of chars)

So I'm trying to make a char**, I fully understand how it works in the background and all that stuff but I don't seem to understand how to write the code for it. I want to make a pointer to an array of chars which has a name in it. I need help with storing a string in it (using strcpy() ) and print it after that.
char** name = (char**)malloc((strlen("MyName") + 1) * sizeof(char*));
strcpy(name, "MyName"); // I get an error right here
If you really want a pointer to an char array, you could do the following:
char** name = (char**)malloc(sizeof(char*)); //initialize the pointer
*name = (char*)malloc((strlen("MyName") + 1) * sizeof(char)); //initialize the array
strcpy(*name, "MyName");
So I'm trying to make a char**, I fully understand how it works in the
background and all that stuff but I don't seem to understand how to
write the code for it.
Umm... No, not quite.
To declare a pointer-to-char, you simply decalre:
char *name = malloc (strlen("MyName") + 1);
Why? When you make your call to malloc, malloc allocates a block of memory providing strlen("MyName") + 1 bytes and returns the starting address to that block of memory -- which you assign to name. You then can copy "MyName" to name (with 1-byte remaining for the nul-terminating character). The approach would be:
size_t len = strlen ("MyName");
char *name = malloc (len + 1); /* allocate len + 1 bytes */
if (name == NULL) { /* validate EVERY allocation */
perror ("malloc-name");
/* handle error by returning or exiting */
}
memcpy (name, "MyName", len + 1); /* no need to scan again for \0 */
/* do something with name - here */
free (name); /* don't forget to free name when you are done */
What then does char** do?
When you are dealing with a pointer-to-pointer-to-char, you must first allocate for some number of pointers, then you can allocate and assign a block of memory to each of the pointers and use each pointer just as you have used name above.
For example:
/* array of ponters to string-literals for your source of strings */
char *band[] = { "George", "Ringo", "Paul", "John" };
char **names;
size_t nmembers = sizeof band / sizeof *band;
/* allocate nmembers pointers */
names = malloc (nmembers * sizeof *names);
if (names == NULL) { /* validate EVERY allocation */
perror ("malloc-name_pointers");
/* handle error by returning or exiting */
}
/* now loop allocating for each name and copy */
for (size_t i = 0; i < nmembers; i++) {
size_t len = strlen (band[i]); /* get length */
names[i] = malloc (len + 1); /* allocate */
if (names[i] == NULL) { /* validate EVERY allocation */
perror ("malloc-names[i]");
/* handle error by returning or exiting */
}
memcpy (names[i], band[i], len + 1);/* no need to scan again for \0 */
}
/* output each */
for (size_t i = 0; i < nmembers; i++)
printf ("member[%zu]: %s\n", i + 1, names[i]);
Freeing names is a two step process. You must free the memory allocated to each of the names pointers and then free the pointers themselves, e.g.
for (size_t i = 0; i < nmembers; i++)
free (names[i]); /* free each allocated names[i] */
free (names); /* free pointers */
Now hopefully you more closely "... fully understand how it works". Let me know if you have any questions.
First thing you should understand is that declaring a variable as a single pointer or a double pointer (or any other n pointer) doesn't actually tell whether the underlying variable holds a single value or an array of values.
Single pointer points to a memory address on which actual value is stored. Double pointer points to a memory address on which single pointer is stored, and so on.
Now, to make a pointer to an array of char pointers you can use a single char pointer (char*) but I recommend to use double char pointer (char**) for maintainability purposes.
Consider the following code:
char** names = (char**)malloc(100 * sizeof(char*));
It will allocate memory space for 100 char pointers (char*) on heap and return you a double pointer (char**) to the first single pointer (char*) in that memory space. This means you will be able to save 100 char pointers (or 100 names in your case) inside that memory space. Then you can use them like this:
char* name0 = "First Name"; // Saved on stack
char* name1 = malloc((strlen("Second Name") + 1) * sizeof(char)); // Saved on heap
strcpy(name1, "Second Name");
names[0] = name0;
names[1] = name1;
Also, please note that when saving a string on heap you need to add one more place for null character (manually).

Dereferencing a double pointer and using index operator

I am passing a double pointer of type char ** to a function. Inside that function, I need to dereference the pointer and then index through the character array.
Unfortunately, I am getting a core dump when I try to assign a capital letter back into the array.
I need help on how to do this. (This is not homework, just a personal project.)
void buffer(char **ppline);
int main()
{
char *line="The redcoats are coming!";
buffer(&line);
printf("\nline = %s\n",line);
return(0);
}
void buffer (char **ppline)
{
int i=0;
char a;
for (i=0; i < strlen(*ppline); i++)
{
a = toupper( (*ppline)[i] ); /* THIS LINE CAUSES THE CORE DUMP */
((*ppline)[i]) = a;
}
return;
}
A string literal in "" is constant. You cannot modify it as you're doing, as that is undefined behavior. Try this, which allocates storage and copies the string literal into it:
void buffer(char **ppline);
int main()
{
char line[] = "The redcoats are coming!";
buffer(&line);
printf("\nline = %s\n",line);
return(0);
}
void buffer (char **ppline)
{
int i=0;
char a;
for (i=0; i < strlen(*ppline); i++)
{
a = toupper( (*ppline)[i] ); /* THIS LINE CAUSES THE CORE DUMP */
((*ppline)[i]) = a;
}
return;
}
Stack, heap, datasegment(and BSS) and text segement are the four segments of process memory. All the local variables defined will be in stack. Dynmically allocated memory using malloc and calloc will be in heap. All the global and static variables will be in data segment. Text segment will have the assembly code of the program and some constants.
In these 4 segements, text segment is the READ ONLY segment and in the all the other three is for READ and WRITE.
char []a="The redcoats are coming!"; - This statemnt will allocate memory for 25 bytes in stack(because local variable) and it will keep all the 24 characters plus NULL character (\0) at the end.
char *p="The redcoats are coming!"; - This statement will allocate memory for 4 bytes(if it is 32 bit machine) in stack(because this is also a local variable) and it will hold the pointer of the constant string which value is "The redcoats are coming!". This byte of constant string will be in text segment. This is a constant value. Pointer variable p just points to that string.
Now a[0] (index can be 0 to 24) means, it will access first character of that string which is in stack. So we can do write also at this position. a[0] = 'x' This operation is allowed because we have READ WRITE access in stack.
But p[0] = 'x' will leads to crash, because we have only READ access to text segement. Segmentation fault will happen if we do any write on text segment.
But you can change the value of variable p, because its local variable in stack. like below
char *p = "string";
printf("%s", p);
p = "start";
printf("%s", p);
This is allowed. Here we are changing the address stored in the pointer variable p to address of the string start(again start is also a read only data in text segement). If you want to modify values present in *p means go for dynamically allocated memory.
char *p = NULL;
p = malloc(sizeof(char)*7);
strcpy(p, "string");
Now p[0] = 'x' operation is allowed, because now we are writing in heap.

Resources