Changing a static array to a dynamic one with minimal changes? - c

I have a C code that creates an array of char pointers as the following:
char* arr[100];
I use each element in this array to point to some string that is being calculated by another function. So basically arr[0] would point to string1 and arr[1] to string2, etc.
This works just fine. However I'm now asked to be more flexible by having the user to specify the number of strings as a parameter.
How can I do this with minimal changes to my code? I understand that I need to use malloc. However I'm getting a lot of warnings in all of the assignment statements I had before. I changed the declaration of the array as the following:
char* arr = (char*)malloc(n * sizeof(char*)); //where n is provided by user
I thought that I only needed to change the declaration. Now all of the assignment statements are giving warnings ("assignment makes integer from pointer without a cast"). The following is an example of an assignment statement:
arr[i] = str; //where str is defined as char* and is calculated by another function
Am I missing something here?

If you're looking to create an array of char *, you need a char **arr. Think of it as an array of char * -- if you had an array of int, you would have int *. Since you have an array of char *s, you need char **.
char** arr = malloc(n * sizeof(char*));

You are declaring arr as a pointer to char: either a single string or, if you prefer, an array of chars.
To allocate an array of pointers, declare arr as
char **arr = malloc(n * sizeof(char *));
By the way, remove the cast: it is unnecessary in C. See also Question 7.7 in the comp.lang.c FAQ.

Don't forget that string is an array too (char *), so u will need array of pointers, which should look like this:
char** arr = (char**)malloc(n * sizeof(char*));

you want to declare arr as as char ** since you are pointing to an array of pointers. If you declare arr only as char * (not char ** or char *[]) you only have one "string".

Related

Building char array from a string (C)

I am writing a simple function in C that should build a char array from string "abc" – so it should build {'a','b','c'} – and return a pointer to that array. Here is my code for this function:
char * makeArr()
{
static char arr[3];
sprintf(arr, "%s\n", "abc");
return arr;
}
Problems occur when I call this method in main:
int main(int argc, char *argv[])
{
char *arr[3];
arr = makeArr();
return 0;
}
The compiler is complaining about casting / conflicting types. I've been playing with pointers, casting and dereferencing for quite a while now, but can't seem to get it to work. Please let me know where my logic is wrong.
Hmm ... there are several errors in this code. Let's start with the most obvious your compiler complains about:
char *arr[3];
This line declares arr to be an array of three pointers to char. What you return from your function is a single pointer to a char -> doesn't match.
Next:
static char arr[3];
sprintf(arr, "%s\n", "abc")
Here you reserve 3 chars. the sprintf() will write 5 chars. %s is replaced by the 3 characters in your string literal "abc". You add a newline character and then a 0 is added as the marker for the end of the "string". Makes 5. This btw is undefined behavior. You write past the end of your array. Code like this can be compiled, but there's no guarantee at all about what will happen at runtime.
Doing a cut here. You should read about arrays and pointers in C. If the text you're reading claims they are the same ... stop right there and find a better text. They aren't.
I'll try to explain this here briefly, so it's suitable for the Q&A style.
An array in C indeed is a contiguous space of several values. char arr[3] means a variable that holds 3 chars.
On the other hand, a char * is just a pointer pointing to a char -- this could be the first element of an array.
In C, you can't pass arrays as function parameters, and you can't return arrays from a function. Trying to do so leads to an implicit conversion: What is actually passed is a pointer to the first element of that array.
I think the last bit of information missing is what a string literal in C is: it's an array (anonymous, e.g., it doesn't have a name) containing all the characters in the double quotes plus a 0 appended. The 0 marks the end of a "string" in C.
In an expression, a string literal evaluates to a pointer to the first element.
So, something like this:
char *foo = "bar";
will lead to foo pointing to the b of the array. It's like writing
static const char no_name_0[] = { 'b', 'a', 'r', 0 };
char *foo = &(no_name_0[0]);
Among other things, you confused:
char arr[3]; // array of 3 chars.
and,
char *arr[3]; // array of 3 pointers to char.
In main(), you should only write char *arr;
Firstly, char arr[3]; is too snall to store "abc\n". It must have at least 5 elements including terminating null-character.
Then, char *arr[3]; is a 3-element array of char*.
You should assign makeArr()'s return value (it has char* type) to arr[0] or another element, or you should change the type of arr in main function to char*, which is the same type as makeArr()'s return value.
Moreover, this makeArr() doesn't make any array and returns (a pointer to) the existing array. Yoy should use malloc() to "make an array".
UPDATE:
Assigning a value of char* to the array char arr[10]; seems invalid in C.
You should use strcpy() or strncpy() (safer than strcpy()) to copy the string stored in the array between arrays.
Pass the array as an argument and modify it in the called function, would be easier. If you're statically creating the array and there's no need to allocate memory, don't, just pass around your pointers to the functions to be modified by reference
void makeArr(char arr[]){
sprintf(arr, "%s\n", "abc");
}
Simply pass the existing declared array to the makeArr function...
int main(int argc, char *argv[]) {
char arr[10];
makeArr(arr);
return 0;
}
You couldn't assign the result of makeArr to arr. I guess that's your casting error. Oversimplifying, arr points to the place on the stack where the array of 10 characters is allocated. So, I'd pass in arr to makeArr as a char*. So, you'd end up with something like this:
#include <stdio.h>
char * makeArr(char *arr)
{
sprintf(arr, "%s\n", "abc");
return arr;
}
int main(int argc, char *argv[])
{
char arr[10];
makeArr(arr);
printf("%s\n", arr);
return 0;
}

Extremely confused about the role of triple pointers

int main()
{
char** subject_array;
char** courses_array;
initialize(subject_array, courses_array);
}
void initialize(char*** subject_array, char*** courses_array)
{
int i;
*subject_array = (char**) malloc(100 * sizeof(char*)); // 100 char pointers
*courses_array = (char**) malloc(100 * sizeof(char*));
for(i = 0; i < 100; i++) //malloc for subject_array
{
(*subject_array)[i] = (char*) malloc(4 * sizeof(char)); // 4 chars for each
(*courses_array)[i] = (char*) malloc(6 * sizeof(char)); // char pointer
}
} //void initialize
My question is: Why is there a discrepancy between the declared double pointers in main and the triple pointers in the initialize function? I think the triple pointer allows me to modify where the 2d array points.
My assignment gives these requirements:
Since you will be changing to where the pointers point, this will involve triple pointers for subjects and
courses!
The above code takes care of bolded requirement but I have absolutely no idea what this even means.
Can someone break it down to me? Does that mean I can modify contents of the 2d arrays of subject_array and courses_array? Such as swapping?
But I can do that already with just double pointers making a 2d array! WHY triple pointers?
First of all, the code is incorret, because initialize asks for char***'s and main gives it char**'s. To add another "pointer level", you take the address of whatever you want to give it to. So, the last line of main shall read initialize(&subject_array, &courses_array) (or shall it be return 0?)
After all, if you don't need to modify the variable subject_array and courses_array themselves, not what they point to, you may remove those pointers. And you actually do modify those variables themselves by means of *var = malloc(...). And, as I already noted, the only problem is that the arguments to initialize are char***, char***, not char**, char** as main is doing.

How should i cast structure of char pointer array into array of array of char?

struct command
{
char *abc[1000];
};
One of the variable is defined in a structure. This char pointer array contains the value after reading the value from file. For example {123,121}.
Now I want to cast these value in array of array of char, something like this:
char a1[][1000]= s1->abc[j];
I am not sure about the syntax... So how should I cast these values in array abc in a1.
If I understand correctly you have an array of 1000 char*, that might have different length (in your example, length is 2). And s1 type is struct command.
Then I think you meant:
char a1[1000][] = s1->abc;
Or:
char a1[] = s1->abc[j];
But I am not sure why you would want to do that instead of:
char * a1[1000] = s1->abc;
Or
char ** a1 = s1->abc
Be careful with indexes though...

Dynamic memory allocation for pointer arrays

I'm am trying to write a program that reads in a series of strings from a text file and stores these in an array of strings, dynamically allocating memory for each element. My plan was to store each string in an array using a pointer and then grow the array size as more were read in. I am having trouble to understand why my test code below is not working. Is this a workable idea?
char *aPtr;
aPtr =(char*)malloc(sizeof(char));
aPtr[0]="This is a test";
printf("%s",aPtr[0]);
In C a string is a char*. A dynamic array of type T is represented as a pointer to T, so for char* that would be char**, not simply a char* the way you declared it.
The compiler, no doubt, has issued some warnings about it. Pay attention to these warnings, very often they help you understand what to do.
Here is how you can start your testing:
char **aPtr;
int len = 1; // Start with 1 string
aPtr = malloc(sizeof(char*) * len); // Do not cast malloc in C
aPtr[0] = "This is a test";
printf("%s",aPtr[0]); // This should work now.
char *str; //single pointer
With this you can store one string.
To store array of strings you Need two dimensional character array
or else array of character pointers or else double pointer
char str[10][50]; //two dimensional character array
If you declare like this you need not allocate memory as this is static declaration
char *str[10]; //array of pointers
Here you need to allocate memory for each pointer
loop through array to allocate memory for each pointer
for(i=0;i<10;i++)
str[i]=malloc(SIZE);
char **str; //double pointer
Here you need to allocate memory for Number of pointers and then allocate memory for each pointer .
str=malloc( sizeof(char *)*10);
And then loop through array allocate memory for each pointer
for(i=0;i<10;i++)
str[i]=malloc(SIZE);
char * aPtr;
is as pointer to a character, to which you allocated memory to hold exactly 1 character.
Doing
aPrt[0] = "test";
you address the memory for this one characters and try to store the address of the literal "test" to it. This will fail as this address most likley is wider then a character.
A fix to your code would be to allocate memory for a pointer to a character.
char ** aPtr = malloc(sizeof(char *));
aPtr[0] = "test";
printf("%s", aPtr[0]);
Are more elegant and more over robust approach would be to allocate the same (as well as adding the mandatory error checking) by doing:
char ** aPtr = malloc(sizeof *aPtr);
if (NULL == aPtr)
{
perror("malloc() failed");
exit(EXIT_FAILURE);
}
...
You are doing it totally wrong. The correct version of your code should be like this:
int main ()
{
char *aPtr;
aPtr =(char*)malloc(20*sizeof(char));
aPtr ="This is a test";
printf("%s",aPtr);
}
You can use pointer array. if you want to store multiple string. Yes I know using for loop will be easy. But I am trying to explain in simple way even a beginner can understand.
int main ()
{
char *aPtr[10];
aPtr[0] =(char*)malloc(20*sizeof(char));
aPtr[0] ="This is a test";
aPtr[1] =(char*)malloc(20*sizeof(char));
aPtr[1] ="This is a test2";
printf("%s\n%s\n",aPtr[0],aPtr[1]);
}

memory allocation for array of pointers

I need to allocate memory for a pointer which needs to be used as a 2d array.I know how to allocate memory for char pointers and int pointers I am confused how memory is allocated of a array of pointers.A pictorial representation of the reason would be very helpful,also is the code below fine?
char *names[5];
for(i=0;i<5;i++)
{
names[i]=(*char)malloc(sizeof(char));
}
No, this is not because you are allocating the array assuming a dimension of just 1 element of primitive type char (which is 1 byte).
I'm assuming you want to allocate 5 pointers to strings inside names, but just pointers.
You should allocate it according to the size of the pointer multiplied by the number of elements:
char **names = malloc(sizeof(char*)*5);
You don't need to allocate them one by one with a loop. Note that you need to specify that it is a pointer-of-pointers by using **
What you're doing is allocating space for 5 chars. You could write this and it'll have the same result:
char *names = (char *)malloc(sizeof(char) * 5);
If you want to have an array of pointers, I think this'd be the best code
char **names = (char **)malloc(sizeof(char *) * 5);
I'm not a super-coder, but as what I now, this is the right solution.
Also, in short you can do the following too in this case for allocating storage for five characters
names = (char*)malloc(5 * sizeof(char))
Emphisizing what Jack said in in the end: his code works only if the array is declared as a pointer-of-pointers by using **.
When the array is declared as
char *names[5];
I guess the right way of allocating memory is almost as Ak1to did, but multiplying by the wanted size of the string of chars:
char *names[5];
for(i=0;i<5;i++)
{
names[i]=(char *)malloc(sizeof(char)*80);
}
else the compiler throws an error about incompatible types.

Resources