I have the following C code which works:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
int pw = sizeof(char*); // width of pointer (to char)
int num;
int first = 1;
int size = 0;
int incr = 10;
char *(*arr)[]; // pointer to array of pointers to char */
test(char* s, int i)
{
int j;
char *(*newarr)[]; // pointer to array of pointers to char
if (first) { // first time
arr = malloc(pw*incr); // malloc array
first = 0; // skip from now on
size = incr; // save the size
}
if (i >= size) { // out of space
newarr = malloc(pw*(size+incr)); // get incr bigger space
for (j=0; j<size; j++) // copy the elements from the old
(*newarr)[j] = (*arr)[j]; // array to new array
free(arr); // free the old array space
arr = newarr; // point old array to new array
size = size+incr;
};
int len = strlen(s); // length of s
(*arr)[i] = malloc(len+1); // assign pointer to pointer array element
strcpy((*arr)[i], s); // copy s to array
// both arguments must be pointers
printf("%d\t%s\n", i, (*arr)[i]);
};
main()
{
char* s = "this is a string";
for (num=0; num<30; num++) // add 30 pointers to s to *arr
test(s, num);
for (num=0; num<30; num++)
printf("%d\t%s\n", num, (*arr)[num]); // print out what they point to
};
It prints out 'i\tthis is a string' for 'i' from 0 to 29 twice. What I want to do is pass 'arr' from the top of the file as an argument of 'test'. The reason I want to do that is because I want to pass several different arrays all of which are declared the same way. If I make the minimal changes to do that I get:
0 this is a string
Segmentation fault (core dumped)
Here is the output of the diff command which shows the minimal changes:
13c13
< char *(*arr)[]; // pointer to array of pointers to char */
---
> char *(*jarr)[]; // pointer to array of pointers to char */
15c15
< test(char* s, int i)
---
> test(char* s, int i, char *(*arr)[])
52c52
< test(s, num);
---
> test(s, num, jarr);
54,55d53
< for (num=0; num<30; num++)
< printf("%d\t%s\n", num, (*arr)[num]); // print out what they point to
In other words everything is the same except for renaming 'arr' as 'jarr' and passing it to 'test'.
Thanks in advance,
Mike
The trouble occurs when you call:
test(s, num, jarr);
You are passing jarr by value. Inside the function, you are reallocating (the hard way — why not use realloc() which does the copying for you?) the array, but that change does not affect the value of jarr 'in main()' because it was passed by value. The second time through the loop, you are still passing a null pointer to the function, but you are then dereferencing that null pointer, which is bad news.
How to fix?
Fair question...I'm not sure if the old "well, if I want to get to there, I wouldn't start from here" gag passes muster.
The 'simplest' change is to revise the call:
jarr = test(s, num, jarr);
and then 'just' revise the function so that it returns a pointer to an array of character pointers. That is a very esoteric function. My brain's not awake (insufficient caffeine), so I used an intermediate typedef to get around the problem of how to write the function declaration and definition:
typedef char *(ArrayString[]);
ArrayString *test3(char *s, int i, char *(*arr)[]);
ArrayString *test3(char *s, int i, char *(*arr)[]) { (*arr)[i] = s; return arr; }
It compiles without warnings; that isn't a guarantee that it's correct.
The primary alternative is to pass a pointer to a pointer to an array of char pointers to the function, which is even more esoteric.
However, both of these are 'starting from here' solutions. You'd do better, on the whole, to devise a different way of handling things. Pointers to arrays are certainly a part of C, but they are at the outer edges of C and you should generally assume that if your design calls for their use, then your design is probably not the best. You should use a simpler char ** (or, perish the thought, char ***; triple indirection is best avoided too, but that isn't always possible).
You seem to have misunderstood how arrays and pointers works. Lets say you want a dynamic array of strings, that is basically a pointer to a pointer of char:
char **arr = NULL;
To allocate memory for that you do e.g.
arr = malloc(sizeof(char *) * current_size);
Now you have an "array" of character pointers. Lets say you want each of these to be a specific string str:
for (int i = 0; i < current_size; i++)
{
arr[i] = strdup(str);
}
Oh, now you need to increase the number of strings, all initialized to the same string as before:
size_t new_size = current_size + 10;
arr = realloc(arr, sizeof(char *) * new_size);
for (int i = current_size; i < new_size)
{
arr[i] = strdup(str);
}
The problem now is that you want to do all of the above in a separate function. It's first now that you have to add another indirection.
I think you can do a double check on the first malloc value assigned to jarr both in the test(s, 0, jarr) and out of the test(s, 0, jarr); the jarr assignement is not successful since you change the pointer value in the passing by value.
Related
This is what I expect my string array s to be after the program is run: {"#0", "#1", "2"}.
This is what I am getting: {"#2", "#2", "2"}.
How do I modify this code so that I can get {"#0", "#1", "#2"} in the main after the function is executed?
What am I doing wrong? Please help.
#include <stdio.h>
void func(char **s){
for(int i=0; i<3; i++){
char buf[10];
snprintf(buf, 10, "#%d",i);
s[i]=buf;
}
}
int main()
{
char *s[3];
func(s);
for(int i=0; i<3; i++){
printf("%s", s[i]);
}
return 0;
}
First, you have every element in your array pointing to the same character array.
Second, they are all pointing to a local character array. This leads to undefined behavior.
Local variables in functions get allocated on the stack. When the function call is over, that memory may be overwritten with some other value.
Given two pointers p and q, the statement:
p = q;
doesn't copy the contents of the memory pointed to by q to the contents of the memory pointed to by p. It copies the pointer values, such that both p and q now point to the same memory, and any change to the memory via p is reflected when q is used.
That being said, the statement:
char buf[10];
declares buf to be an array of 10 chars. It has a lifetime corresponding to the execution of its block of definition. Once the function returns, it's destroyed and s is now indeterminate. Indeterminate pointers lead to undefined behaviour.
Possible Solutions:
standard strcpy
POSIX's strdup (which will be included in C23)
Note that the strdup() function returns a pointer to a new string which is
a duplicate of the provided string. Memory for the new string is obtained with malloc, and must be freed by the calling process with free.
#Chris’s answer tells you what is wrong.
To fix it, you have options. The simplest is to make the argument array have strings (char arrays) that are big enough for your uses:
#define MAX_STR_LEN (9+1) // Every string’s capacity is 9+1 characters
void func(size_t n, char array_of_string[][MAX_STR_LEN])
{
for (size_t i=0; i<n; i++)
{
snprintf(array_of_string[i], MAX_STR_LEN, "#%d", (int)i); // use the extant string
}
}
int main(void)
{
char array_of_string[3][MAX_STR_LEN] = {{0}}; // Array of 3 strings
func(3, array_of_string);
...
return 0;
}
If you want to play with dynamic char * strings, life gets only a little more complicated:
void func(size_t n, char *array_of_string[])
{
for (size_t i=0; i<n; i++)
{
free(array_of_string[i]); // free any pre-existing string
array_of_string[i] = calloc( 10, 1 ); // allocate our new string
if (!array_of_string[i]) fooey(); // always check for failure
snprintf(array_of_string[i], 10, "#%d", (int)i); // use the new string
}
}
int main(void)
{
char *array_of_string[3] = {NULL}; // Array of 3 dynamic strings, all initially NULL
func(3, array_of_string);
...
for (size_t i=0; i<3; i++) // Don’t forget to clean up after yourself
free(array_of_string[i]);
return 0;
}
Ultimately the trick is to manage the size of your strings, remembering that a string is itself just an array of char. You must ensure that there is enough room in your character array to store all the characters you wish. (Good job on using snprintf()!
Also remember that in C any argument of the form array[] is the same as *array. So our functions could have been written:
void func(size_t n, char (*array_of_string)[MAX_STR_LEN])
or
void func(size_t n, char **array_of_string)
respectively. The first is an uglier (harder to read) syntax. The second is nicer, methinks, but YRMV.
Finally, if you are using C99 (or later) you can tell the compiler that those arguments are, actually, arrays:
void func(size_t n, char array_of_string[n][MAX_STR_LEN])
or
void func(size_t n, char *array_of_string[n])
MSVC does not support that syntax, though, and probably never will, alas.
{ // start of a new scope
char buf[10]; // a variable with automatic storage duration
// ...
} // end of scope - all automatic variables end their life
In your code, you make pointers point at buf which has seized to exist (3 times) at the } in the for loop. Dereferencing (reading from the memory those pointers point at) those pointers afterwards makes your program have undefined behavior (anything could happen).
What you can do is to allocate and release memory dynamically using malloc and free.
When sending in a pointer to the first element in an array of elements to a function like you do, it's also customary to provide the length of the array (the number of elements in the array) to the function.
It could look like this:
#include <stdio.h>
#include <stdlib.h>
// A macro to calculate the number of elements in an array
// sizeof (x) - the number of bytes the whole array occupies
// sizeof *(x) - the size of the first element in the array
// (all elements have equal size)
// The result of the division is the number of elements in the array.
#define SIZE(x) (sizeof (x) / sizeof *(x))
void func(char *s[], size_t len) {
for (size_t i = 0; i < len; i++) {
// calculate the required length for this string
size_t req = snprintf(NULL, 0, "#%zu", i) + 1; // +1 for '\0'
// and allocate memory for it
s[i] = malloc(req);
if(s[i] == NULL) exit(1); // failed to allocate memory
snprintf(s[i], req, "#%zu", i);
} // dynamically allocated memory is _not_ released at the end of the scope
}
int main() {
char *s[3];
func(s, SIZE(s));
for (size_t i = 0; i < SIZE(s); i++) {
puts(s[i]);
free(s[i]); // free what you've malloc'ed when you are done with it
}
}
Note that with the use of the macro there is only one hardcoded 3 in the program. Even that could be made into a named constant (#define CHAR_PTRS (3) or enum { CHAR_PTRS = 3 };) to further the ease of reading and maintaining the code.
A non-idiomatic version only accepting a pointer to an array of a fixed (at compile time) size could look like like below. In this example you couldn't accidentally provide a pointer to an array with only 2 char* (which would cause the function to write out of bounds). Instead, it'd result in a compilation error.
#include <stdio.h>
#include <stdlib.h>
// Here `s` is a pointer to an array of 3 char*
void func(char *(*s)[3]) {
for (int i = 0; i < 3; i++) {
(*s)[i] = malloc(10);
if((*s)[i] == NULL) exit(1);
snprintf((*s)[i], 10, "#%d", i);
}
}
int main() {
char *s[3];
func(&s); // &s is a char*(*)[3]
for (int i = 0; i < 3; i++) {
printf("%s\n", s[i]);
free(s[i]);
}
}
#include <stdio.h>
#include <string.h>
void func(char **s){
for(int i=0; i<3; i++){
s[i]=malloc(sizeof(char) * 100);
char buf[10];
snprintf(buf, 10, "#%d",i);
strcpy(s[i], buf);
}
}
int main()
{
char *s[3];
func(s);
for(int i=0; i<3; i++){
printf("%s", s[i]);
}
return 0;
}
This fixed my problem. My understanding is that I assigned memory and then copied the contents of buf to s to the now-present memory.
I'm trying to reset the position of a pointer at the beginning by using a function. My idea was to send to the function the address of the array of strings. By decrementing the pointer it should also be decreased in memory so I should be able again to manipulate my pointer from the beginning once getting back in my main function, but this seems not working and the position remains unaltered.
void reset(char ***g,int count){
for (int i = 0; i < count; i++){
g--;
}
}
and in the main:
char **array_of_strings = malloc etc....
//doing my operations and incrementing the pointer position
reset(&array_of_strings,count); //where count is how many time position of array_of_strings has been incremented
free(array_of_strings); //invalid pointer position
I also assume that making a function which returns a new pointer with the decreased position it's useless because we are not able to free the original pointer yet, it could be useful in another context maybe but not in this one.
You do not need to decrement in a loop. It is simple pointer arithmetic. In the example below you have some examples
char *strings[] = {"111","222","3333","4444", "555", NULL};
char **strptr = strings;
char ** pointerartihm(char **ptr, ssize_t count)
{
return ptr + count;
}
char **threestar(char ***ptr, ssize_t count)
{
*ptr += count;
return *ptr;
}
int main(void)
{
ssize_t count = 0;
while(*strptr) {printf("%s\n", *strptr++); count++;}
//strptr -= count;
//strptr = pointerartihm(strptr, -count);
threestar(&strptr, -count);
printf("\n\n After the \"reset\" - %s\n", *strptr);
}
https://godbolt.org/z/qbvz9G
Your question is basically like this:
int i = calculate_something();
// doing my operations and incrementing i
// how do I get i back to the number I calculated?
And the answer is, you use a separate variable:
int i = calculate_something();
int j = i;
// doing my operations and incrementing j
// now i still has the original number
With pointers:
char **array_of_strings = malloc etc....
char **temp_pointer_to_array_of_strings = array_of_strings;
// doing my operations and incrementing the pointer position of the second one
// now array_of_strings still has the original pointer
free(array_of_strings); // valid
I am new to C and still trying to figure out pointer.
So here is a task I am stuck in: I would like to assign 10 fruit names to a pointer of array and print them out one by one. Below is my code;
#include <stdio.h>
#include <string.h>
int main(){
char *arr_of_ptrs[10];
char buffer[20];
int i;
for (i=0;i<10;i++){
printf("Please type in a fruit name:");
fgets(buffer,20,stdin);
arr_of_ptrs[i]= *buffer;
}
int j;
for (j=0;j<10;j++){
printf("%s",*(arr_of_ptrs+j));
}
}
However after execution this, it only shows me the last result for all 10 responses. I tried to consult similar questions others asked but no luck.
My understanding is that
1) pointer of array has been allocated memory with [10] so malloc() is not needed.
2) buffer stores the pointer to each individual answer therefore I dereference it and assign it to the arr_of_ptrs[i]
I am unsure if arr_of_ptrs[i] gets me a pointer or a value. I thought it is definitely a pointer but I deference it with * the code and assign it to *buffer, program would get stuck.
If someone could point out my problem that would be great.
Thanks in advance
Three erros, 1. You must allocate memory for elements of elements of arr_of_ptrs, now you only allocate the memory for elements of arr_of_ptrs on stack memory. 2. arr_of_ptrs[i]= *buffer; means all of the arr_of_ptrs elements are pointed to same memory address, which is the "buffer" pointer. So all the elements of arr_of_ptrs will be same to the last stdin input string. 3. subsequent fgets() call has potential problem, one of the explaination could be here
A quick fix could be,
#include <stdio.h>
#include <string.h>
int main(){
const int ARR_SIZE = 10, BUFFER_SIZE = 20;
char arr_of_ptrs[ARR_SIZE][BUFFER_SIZE];
char *pos;
int i, c;
for (i = 0; i < ARR_SIZE; ++i) {
printf ("Please type in a fruit name: ");
if (fgets (arr_of_ptrs[i], BUFFER_SIZE, stdin) == NULL) return -1;
if ((pos = strchr(arr_of_ptrs[i], '\n')))
*pos = 0;
else
while ((c = getchar()) != '\n' && c != EOF) {}
}
for (i = 0; i < ARR_SIZE; ++i)
printf("%s\n", arr_of_ptrs[i]);
return 0;
}
The misunderstanding is probably that "Dereferencing" an array of characters, unlike dereferencing a pointer to a primitive data type, does not create a copy of that array. Arrays cannot be copied using assignment operator =; There a separate functions for copying arrays (especially for 0-terminated arrays of char aka c-strings, and for allocating memory needed for the copy):
Compare a pointer to a primitive data type like int:
int x = 10;
int *ptr_x = &x;
int copy_of_x = *ptr_x; // dereferences a pointer to x, yielding the integer value 10
However:
char x[20] = "some text"; // array of characters, not a single character!
char *ptr_x = &x[0]; // pointer to the first element of x
char copy_of_first_char_of_x = *ptr_x; // copies the 's', not the entire string
Use:
char x[20] = "some text";
char *ptr_x = &x[0];
char *copy_of_x = malloc(strlen(ptr_x)+1); // allocate memory large enough to store the copy
strcpy(copy_of_x,ptr_x); // copy the string.
printf("%s",copy_of_x);
Output:
some text
In the main method , i am creating an array of pointers to string
in the add method i am reallocating the array size and adding x elements which i dont know
while coming back to main how can i know the new size of the array , i mean the number of elements int the array ?
Here is my code .. (it has some bugs)
#include <stdio.h>
void add(char ***x);
int main()
{
char **s;
s = (char **) malloc(sizeof(char *));
int i;
add(&s);
for( i=1;i<=?????(**find the new size of the array** );i++)
puts(*s[i]);
return 0;
}
void add(char ***x)
{
- ** // alter arry add x random datas to the array of string pointer**
/*
s[1]="Hello";
s[2]="Need";
s[3]="a help";
s[4]="and help";
s[5]="for the help";
*/
char **data;
int i = 0;
for (i = 1; i <= 5; i++)
{
data = (char **) realloc(*x, 1 * sizeof(char *));
data[i] = (char *) malloc(i * sizeof(char *));
strcpy(data[i], "first");
}
}
can some one please point and fix the bug in the code..
(Sidenote:
can some one please point and fix the bug in the code..
hey, isn't that what debuggers are for?)
Long story short, keep track of it manually:
char **func_that_reallocs(char **ptr, size_t *sz)
{
char **tmp = realloc(ptr, new_size * sizeof(*ptr));
*sz = new_size;
return tmp;
}
And please do not cast the return value of malloc()!
Always add one entry more to the array as needed and set this additional last entry to NULL.
Then write a function which scans the array until it find this NULL-pointer and return the number of entries counted up until then and you are done.
It's the same concept as for a C-"string", with the only difference of using a NULL instead of '\0' as (array-)terminator.
Some people call this last element also the "stopper"-element.
The positive thing about this approach is, one does not have to keep the array's size in a different variable, which might get out of sync with the real size of the array: The size is implicitly given by the array itself.
I am having trouble understanding how to assign memory
to a double pointer.
I want to read an array of strings and store it.
char **ptr;
fp = fopen("file.txt","r");
ptr = (char**)malloc(sizeof(char*)*50);
for(int i=0; i<20; i++)
{
ptr[i] = (char*)malloc(sizeof(char)*50);
fgets(ptr[i],50,fp);
}
instead of this I just assign a large block of memory and
store the string
char **ptr;
ptr = (char**)malloc(sizeof(char)*50*50);
would that be wrong? And if so why is it?
Your second example is wrong because each memory location conceptually would not hold a char* but rather a char. If you slightly change your thinking, it can help with this:
char *x; // Memory locations pointed to by x contain 'char'
char **y; // Memory locations pointed to by y contain 'char*'
x = (char*)malloc(sizeof(char) * 100); // 100 'char'
y = (char**)malloc(sizeof(char*) * 100); // 100 'char*'
// below is incorrect:
y = (char**)malloc(sizeof(char) * 50 * 50);
// 2500 'char' not 50 'char*' pointing to 50 'char'
Because of that, your first loop would be how you do in C an array of character arrays/pointers. Using a fixed block of memory for an array of character arrays is ok, but you would use a single char* rather than a char**, since you would not have any pointers in the memory, just chars.
char *x = calloc(50 * 50, sizeof(char));
for (ii = 0; ii < 50; ++ii) {
// Note that each string is just an OFFSET into the memory block
// You must be sensitive to this when using these 'strings'
char *str = &x[ii * 50];
}
char **ptr;
fp = fopen("file.txt","r");
ptr = (char**)malloc(sizeof(char*)*50);
for(int i=0; i<50; i++)
{
ptr[i] = (char*)malloc(sizeof(char)*50);
fgets(ptr[i],50,fp);
}
fclose(fp);
may be your typo mistake but your loop should be of 50 instead of 20 if you are looking for 50 x 50 matrix. Also after allocation of memory mentioned above you can access the buffer as ptr[i][j] i.e in the 2D format.
A double pointer is just a pointer to another pointer. So you can allocate it like this:
char *realptr=(char*)malloc(1234);
char **ptr=&realptr;
You have to keep in mind where your pointer is stored at (in this example the double pointer points to a pointer variable on the stack so it's invalid after the function returns).
i will give one example, which might clear of the doubt,
char **str; // here its kind a equivalent to char *argv[]
str = (char **)malloc(sizeof(char *)*2) // here 2 indicates 2 (char*)
str[0]=(char *)malloc(sizeof(char)*10) // here 10 indicates 10 (char)
str[1]=(char *)malloc(sizeof(char)*10) // <same as above>
strcpy(str[0],"abcdefghij"); // 10 length character
strcpy(str[1],"xyzlmnopqr"); // 10 length character
cout<<str[0]<<endl; // to print the string in case of c++
cout<<str[1]<<endl; // to print the string in case of c++
or
printf("%s",str[0]);
printf("%s",str[1]);
//finally most important thing, dont't forget to free the allocated mem
free(str[0]);
free(str[1]);
free(str);
other simpler way to memorize
Case -1 :
step-1 : char *p;
step -2 :
please read it like below
char (*p); ==> p is a pointer to a char
now you just need to do malloc for the type (step-2) without braces
i.e., p = malloc(sizeof(char) * some_len);
Case -2 :
step-1 : char **p;
step -2 :
please read it like below
char* (* p); ==> p is a pointer to a char *
now you just need to do malloc for the type (step-2) without braces
i.e., p = malloc(sizeof(char *) * some_len);
Case -3 :
No one uses this but just for sake of explanation
char ***p;
read it as,
char** (*p); ==> p is a pointer to a char** (and for this check case-2 above)
p = malloc(sizeof(char**) * some_len);
Adding to Pent's answer, as he correctly pointed out, you will not be able to use this double pointer once the function returns, because it will point to a memory location on the function's activation record on stack which is now obsolete (once the function has returned). If you want to use this double pointer after the function has returned, you may do this:
char * realptr = (char *) malloc(1234);
char ** ptr = (char **) malloc(sizeof(char *));
*ptr = realptr;
return ptr;
The return type of the function must obviously be char ** for this.
well, this is how I do it:
#include <stdlib.h>
int main(void)
{
int i = -1; // just a counter
int j = 5; // how many strings
char *s[j];
while(++i < j)
s[i] = malloc(sizeof(char*)); // allocating avery string separately
return (0);
}
this also works:
char **allocate(int lines)
{
int i = -1;
char **s = malloc(sizeof(char *) * lines); // allocating lines
while (++i < lines)
{
s[i] = malloc(sizeof(char*)); // alicating line
scanf("%s", s[i]);
}
return (s);
}
int main(int ac, char *av[])
{
int lines = 5; // how many lines
char **s = allocate(lines);
return (0);
}
Double pointer is, simply put, a pointer to a pointer,
In many cases it is used as an array of other types.
For example, if you want to create an array of strings you can simply do:
char** stringArray = calloc(10, 40);
this will create an array of size 10, each element will be a string of length 40.
thus you can access this by stringArray[5] and get a string in the 6th position.
this is one usage, the others are as mentioned above, a pointer to a pointer, and can be allocated simply by:
char* str = (char*)malloc(40);
char** pointerToPointer = &str //Get the address of the str pointer, valid only in the current closure.
read more here:
good array tutorial