I have some code that stack dumps when using sprintf to copy a a pointer to strings. I am trying to copy the contents of animals into a new pointer array called output. However, I get a stack dump.
What should be in the output is the following: new animal rabbit new animal horse new animal donkey
An I going about this the right way?
Many thank,s
#include <stdio.h> #include <string.h> #include <stdlib.h> void p_init(const char **animals, char **output); int main(int argc, char **argv) { char *animals[] = {'rabbit', 'horse', 'donkey', '\0'}; char **prt_animals = animals; char *output[sizeof(*animals)]; /* print the contents here */ while(*prt_animals) { printf('Animal: %s\n', *prt_animals++); } /* copy and update in the output buffer */ p_init(*&animals, *&output); getchar(); return 0; void p_init(const char **animals, char **output) { while(*animals) { sprintf(*output, 'new animal %s', *animals); *output++; } }
The array
animalsis an array of pointers. It is not an array of buffers of some size. Therefor, if you doYou will get the sizeof of the first element of that array. Equivalent to
Because your array stores pointers. So, in the line that reads
You allocate 4 or 8 pointers in one array (depends on how wide a pointer on your platform is. Usually it’s either 4 or 8). But that’s of course not senseful! What you wanted to do is create an array of pointers of the same size as
animals. You will have to first get the total size of the animals array, and then divide by the size of one elementNow, that is what you want. But the pointers will yet have indeterminate values… Next you pass the array using
*&animals(same for the other). Why that? You can passanimalsdirectly. Taking its address and then dereference is the same as doing nothing in the first place.Then in the function you call, you copy the strings pointed to by elements in
animalto some indeterminate destination (remember the elements of theoutputarray – the pointers – have yet indeterminate values. We have not assigned them yet!). You first have to allocate the right amount of memory and make the elements point to that.Addition, about the sizeof above
There’s one important thing you have to be sure about. It’s the way we calculate the size. Whatever you do, make sure you always have enough room for your string! A C string consists of characters and a terminating null character, which marks the end of the string. So,
*outputshould point to a buffer that is at least as large so that it contains space for'new animal 'and*animals. The first contains 11 characters. The second depends on what we actually copy over – its length is whatstrlenreturns. So, in total we needspace for all characters including the terminating null. Now it’s not good style to hardcode that number into your code. The prefix could change and you could forget to update the number or miscount about one or two characters. That is why we use
sizeof, which we provide with the string literal we want to have prepended. Recall that asizeofexpression evaluates to the size of its operand. You use it inmainto get the total size of your array before. Now you use it for the string literal. All string literals are arrays of characters. string literals consist of the characters you type in addition to the null character. So, the following condition holds, becausestrlencounts the length of a C string, and does not include the terminating null character to its lengthWe don’t have to divide by the size of one element, because the sizeof char is one anyway, so it won’t make a difference. Why do we use
sizeofinstead of strlen? Because it already accounts for the terminating null character, and it evaluates at compile time. The compiler can literally substitute the size that the sizeof expression returns.