Array with char arrays - c

I want to create an array with malloc and then assign the fields of the array an output of fgets.
char *words;
words = (char *)malloc(lines*sizeof(char));
int k = 0;
words[k] = (char *)malloc(mysize*sizeof(char));
This won't work because of the missing pointer I guess. What can I do?

I want to create an array with malloc and then assign the fields of the array an output of fgets. ? Then hopefully you should declare words as double pointer or array of char pointer.
One way is, by using array of char pointer like below.
char *words[lines]; /* array of pointer, lines is nothing but number of line in file */
for(int row = 0;row < lines; row++) {
/* allocate memory for each line */
words[row] = malloc(mysize);/* mysize is nothing but lines has max no of char i.e max no of char */
/* now read from file */
fgets(word[row],mysize,fp);/* reading from file(fp) & store into word[0],word[1] etc */
}
Or you can use double pointer like char **words; also.
And once job is done, at last don't forget to free the dynamically allocated memory.

Related

Best way to initialize an array of strings to pass it to a function

I need to intialize an empty array of strings with fixed size ( 3 by 100 for example), pass it to a function to fill it with data and perform things like strcpy(), strcmp(), memset() on it. After the function is terminated I need to be able to read the data from my main().
What I tried so far:
char arrayofstrings[3][100] = {0};
char (*pointer)[3][100] = &arrayofstrings;
function(pointer);
Initalizing an (empty?) array of strings and initializing a pointer on the first element.
int function (char (*pointer)[3][100])
{
strcpy((*pointer)[i], somepointertostring);
strcmp((*pointer)[i], somepointertostring)
memset((*pointer)[i], 0, strlen((*pointer)[i]));
}
Is this a good way to do it? Is there an easier way to do it? Whats up with the brackets around the pointer?
C string functions expect a buffer to be null-terminated. Your arrayofstrings allocation happens on the stack. Depending on your compiler it might be initialized to all zeros or might contain garbage.
The simplest way in your case to make sure string functions won't overrun your buffers is to set the first character of each to 0 (null)
arrayofstrings[0][0] = 0x00;
arrayofstrings[1][0] = 0x00;
arrayofstrings[2][0] = 0x00;
This will give you 3, 100-char buffers that contain a valid empty "string". Note that you can only store 99 "characters" because the last character must be 0x00 (null-terminator).
char (*pointer)[3][100] = &arrayofstrings;
This is unnecessary.
Something to keep in mind about arrays in C is that the [] index is really only there to make things easier for the human programmer. Any array definition is simply a pointer to memory. The values inside the [][]...[] indexes and the type are used by the compiler to allocate the right amount of memory on the stack and do some simple math to come up with the right memory address for the element you want to access.
char arrayofstrings[3][100];
This will allocate sizeof(char)*3*100 bytes on the stack and give you a char* called 'arrayofstrings'. There's nothing special about the char* itself. It would be the same pointer if you had char arrayofstrings[300] or char arrayofstrings[3][10][10] or even long arrayofstrings[75] (char is 1 byte, long is 4 bytes).
Because you declared it as a multidimensional array with [a][b], when you ask for arrayofstrings[x][y], the compiler will calculate ((x*b)+y)*sizeof(type) and add it to the arrayofstrings pointer to get the address of the value you want. But because it's just a pointer, you can treat it like any other pointer and pass it around or cast it to other types of pointer or do pointer math with it.
You don't need the extra level of indirection.
An array, when passed to a function, is converted to a pointer to its first member. So if you declare the function like this:
int function(char (*pointer)[100])
Or equivalently:
int function(char pointer[][100])
Or:
int function(char pointer[3][100])
You can pass the array directly to the function:
function(arrayofstrings);
Then the body could look something like this:
strcpy(pointer[0], "some string");
strcpy(pointer[1], "some other string");
strcpy(pointer[2], "yet another string");
Best way to initialize an array of strings ...
char arrayofstrings[3][100] = {0}; is fine to initialize an array of strings.
In C, initialization is done only at object definition, like above.
Later code like strcpy(), assigns data to the array.
Best way to ... pass it to a function
When the C compiler supports variable length arrays, use function(size_t n, size_t sz, char a[n][sz]).
Add error checks.
Use size_t for array sizing and indexing.
#define somepointertostring "Hello World"
int function(size_t n, size_t sz, char arrayofstrings[n][sz]) {
if (sz <= strlen(somepointertostring)) {
return 1;
}
for (size_t i = 0; i < n; i++) {
strcpy(arrayofstrings[i], somepointertostring);
if (strcmp(arrayofstrings[i], somepointertostring)) {
return 1;
}
// Drop this it see something interesting in `foo()`
memset(arrayofstrings[i], 0, strlen(arrayofstrings[i]));
}
return 0;
}
void foo(void) {
char arrayofstrings[3][100] = {0};
size_t n = sizeof arrayofstrings / sizeof arrayofstrings[0];
size_t sz = sizeof arrayofstrings[0];
if (function(n, sz, arrayofstrings)) {
puts("Fail");
} else {
puts("Success");
puts(arrayofstrings[0]);
}
}
Initalizing an (empty?) array of strings and initializing a pointer on the first element.
The type of &arrayofstrings is char (*)[3][100] i.e. pointer to an object which is a 2D array of char type with dimension 3 x 100. So, this initialisation
char (*pointer)[3][100] = &arrayofstrings;
is not initialisation of pointer with first element of arrayofstrings array but pointer will point to whole 2D array arrayofstrings. That why, when accessing the elements using pointer you need bracket around it -
`(*pointer)[0]` -> first string
`(*pointer)[1]` -> second string and so on..
Is this a good way to do it? Is there an easier way to do it?
If you want pointer to first element of array arrayofstrings then you can do
char (*p)[100] = &arrayofstrings[0];
Or
char (*p)[100] = arrayofstrings;
both &arrayofstrings[0] and arrayofstrings are equivalent1).
Pass it to a function and access the array:
function() function signature should be -
int function (char (*pointer)[100])
// if you want the function should be aware of number of rows, add a parameter for it -
// int function (char (*pointer)[100], int rows)
this is equivalent to
int function (char pointer[][100])
and call it in from main() function like this -
function (p);
In the function() function you can access array as p[0], p[1] ...:
Sample program for demonstration:
#include <stdio.h>
#include <string.h>
#define ROW 3
#define COL 100
void function (char (*p)[COL]) {
strcpy (p[0], "string one");
strcpy (p[1], "string two");
strcpy (p[2], "string three");
}
int main(void) {
char arrayofstrings[ROW][COL] = {0};
char (*pointer)[COL] = &arrayofstrings[0];
function (pointer);
for (size_t i = 0; i < ROW; ++i) {
printf ("%s\n", arrayofstrings[i]);
}
return 0;
}
When you access an array, it is converted to a pointer to first element (there are few exceptions to this rule).

AddressSanitizer error in leetcode practice using c

char * convert(char * s, int numRows){
char rows[numRows][strlen(s)];
memset( rows, '\0', numRows*strlen(s)*sizeof(char) );
int curRow=0;
bool goingDown=false;
int len=0;
char *str=s;
for(char c=*str;c=*str;++str){
len=0;
while(rows[curRow][len]){len++;}
rows[curRow][len]=c;
if(curRow==numRows-1||curRow==0){goingDown=!goingDown;}
if(goingDown){curRow++;}
else{curRow--;}
}
char *zig=malloc(strlen(s)+1);
*zig='\0';
int i=0;
for(char *row;i<numRows;i++){
row=*(rows+i);
zig=strcat(zig,row);
}
return zig;
}`
I am trying to implement the solution in c. Leetcode has thrown this to me:
==26==ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address 0x7ffd37cc1741.
But I have no idea what is the problem. All I could guess is that row variable has something wrong. Test case being "A" 1 .
row: 0x7ffd37cc1740 "A\vI\037\244U"
So how could I fix this code? Trying to learn more about c.
Problem solved now. I shall declare 2d char rows with strlen(s)+1. Thus the row variable would be nul terminated, which would be valid for strcat argument.Thanks!
Your problem (or at least, one of) is in the first line of the function definition.
char rows[numRows][strlen(s)];
declares a 2D char array on the stack. You should not declare variables with size dependent on runtime in the stack (in this case, because of the variables s and numrows passed to the function).
You should instead allocate memory dynamically using malloc or alternatives -
char ** rows = malloc(sizeof(char *)*numrows); // allocate memory to store `num_rows` char pointers
// for each element in rows, create a pointer with num_columns of chars amount of space
for(int i = 0 ; i < num_columns ; i++){
rows[i] = malloc(sizeof(char) * num_columns); // store pointer in rows[i]
// memset this memory as needed
}
// now rows[x][y] will be one char
Note that you will need to allocate one more char than the number of characters in your string to add the null terminator in C char arrays.
This will likely get rid of the buffer overflow error, although your program may contain other flaws.

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).

Double pointer vs array of pointers(**array vs *array[])

Im not clearly sure what is the difference between those 2. My professor wrote that **array is same as *array[] and we were presented an example where he used **array (so after classes I tried exchanging that with *array[] and it didn't work), could anyone tell me if those 2 are actually the same as he wrote?? Anyway the class was about dynamic memory allocation
#As soon as I changed the double pointer, this line started throwing error
lines = malloc(sizeof(char*));
and a few others where the memory is beeing reallocated
#2 Hell yeah, here's the whole code
And for those comments bellow, nope there is nothing inside [] because his statement was
**array = *array[]
BIG UPDATE
I am so sorry for any inconvenience, I was just too tired at the time of writing this post, here is the whole code with no edits
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **lines; // global text buffer, organized as an array of lines
// --------------------------------------------------------------------------------
// initialize global buffer
void initialize()
{
lines = malloc(sizeof(char*));
lines[0] = NULL;
}
// --------------------------------------------------------------------------------
// return number of lines in buffer
int countLines()
{
int count = 0;
while(lines[count++]) ;
return count-1;
}
// --------------------------------------------------------------------------------
// print one line
void printLine(int line)
{
printf("Line %d: %p %p %s\n",line, &lines[line], lines[line], lines[line]);
}
// --------------------------------------------------------------------------------
// print all lines
void printAll()
{
int num_lines = countLines();
int line = 0;
printf("----- %d line(s) ----\n",num_lines);
while (line < num_lines)
printLine(line++);
printf("---------------------\n");
}
// --------------------------------------------------------------------------------
// free whole buffer
void freeAll()
{
int line = countLines();
while (line >= 0)
free(lines[line--]);
free(lines);
}
// --------------------------------------------------------------------------------
// insert a line before the line specified
void insertLine(int line, char *str)
{
int num_lines = countLines();
// increase lines size by one line pointer:
lines = realloc(lines, (num_lines+2) * sizeof(char*));
// move line pointers backwards:
memmove(&lines[line+1], &lines[line], (num_lines-line+1)*sizeof(char*));
// insert the new line:
lines[line] = malloc(strlen(str)+1);
strcpy(lines[line],str);
}
// --------------------------------------------------------------------------------
// remove the specified line
void removeLine(int line)
{
int num_lines = countLines();
// free the memory used by this line:
free(lines[line]);
// move line pointers forward:
memmove(&lines[line], &lines[line+1], (num_lines-line+1)*sizeof(char*));
// decrease lines size by one line pointer:
lines = realloc(lines, num_lines * sizeof(char*));
}
// --------------------------------------------------------------------------------
// insert a string into specified line at specified column
void insertString(int line, int col, char *str)
{
// make room for the new string:
lines[line] = realloc(lines[line], strlen(lines[line])+strlen(str)+1);
// move characters after col to the end:
memmove(lines[line]+col+strlen(str), lines[line]+col, strlen(lines[line])-col);
// insert string (without terminating 0-byte):
memmove(lines[line]+col, str, strlen(str));
}
// --------------------------------------------------------------------------------
// MAIN program
int main()
{
initialize();
printAll();
insertLine(0,"Das ist");
printAll();
insertLine(1,"Text");
printAll();
insertLine(1,"ein");
printAll();
insertLine(2,"kurzer");
printAll();
printf("lines[2][4] = %c\n",lines[2][4]);
insertString(2,0,"ziemlich ");
printAll();
removeLine(2);
printAll();
freeAll();
return 0;
}
If the code you reference in your question was given to you by your professor as an example of the use of pointer arrays of pointers to pointers, I'm not sure how much good that class will actually do. I suspect it was either provided as a debugging exercise or it may have been your attempt at a solution. Regardless, if you simply compile with Warnings enabled, you will find a number of problems that need attention before you advance to debugging your code.
Regarding the code you reference, while you are free to use a global text buffer, you are far better served by not using a global buffer and passing a pointer to your data as required. There are some instances, various callback functions, etc. that require global data, but as a rule of thumb, those are the exception and not the rule.
Your question basically boils down to "How do I properly use an array of pointers and double-pointers (pointer-to-pointer-to-type) variables. There is no way the topic can be completely covered in one answer because there are far too many situations and contexts where one or the other can be (or should be) used and why. However, a few examples will hopefully help you understand the basic differences.
Starting with the array of pointers to type (e.g. char *array[]). It is generally seen in that form as a function argument. When declared as a variable it is followed with an initialization. e.g.:
char *array[] = { "The quick",
"brown fox",
"jumps over",
"the lazy dog." };
char *array[]; by itself as a variable declaration is invalid due to the missing array size between [..]. When used globally, as in your example, the compiler will accept the declaration, but will warn the declaration is assumed to have one element.
The elements of array declared above are pointers to type char. Specifically, the elements are pointers to the string-literals created by the declaration. Each of the strings can be accessed by the associated pointer in array as array[0], ... array[3].
A pointer to pointer to type (double-pointer), is exactly what its name implies. It is a pointer, that holds a pointer as its value. In basic terms, it is a pointer that points to another pointer. It can be used to access the members of the array above by assigning the address of array like:
char **p = array;
Where p[1] or *(p + 1) points to "brown fox", etc.
Alternatively, a number of pointer to pointer to type can be dynamically allocated and used to create an array of pointers to type, that can then be allocated and reallocated to handle access or storage of an unknown number of elements. For example, a brief example to read an unknown number of lines from stdin, you might see:
#define MAXL 128
#define MAXC 512
...
char **lines = NULL;
char buf[MAXC] = {0};
lines = malloc (MAXL * sizeof *lines);
size_t index = 0;
...
while (fgets (buf, MAXC, stdin)) {
lines[index++] = strdup (buf);
if (index == MAXL)
/* reallocate lines */
}
Above you have lines, a pointer-to-pointer-to-char, initially NULL, that is use to allocate MAXL (128) pointers-to-char. Lines are then read from stdin into buf, after each successful read, memory is allocated to hold the contents of buf and the resulting start address for each block of memory is assigned to each pointer line[index] where index is 0-127, and upon increment of index to 128, index is reallocated to provide additional pointers and the read continues.
What makes the topic larger than can be handled in any one answer is that an array of pointers or pointer to pointer to type can be to any type. (int, struct, or as a member of a struct to different type, or function, etc...) They can be used linked-lists, in the return of directory listings (e.g opendir), or in any additional number of ways. They can be statically initialized, dynamically allocated, passed as function parameters, etc... There are just far too many different contexts to cover them all. But in all instances, they will follow the general rules seen here and in the other answer here and in 1,000's more answers here on StackOverflow.
I'll end with a short example you can use to look at the different basic uses of the array and double-pointer. I have provided additional comments in the source. This just provides a handful of different basic uses and of static declaration and dynamic allocation:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
/* array is a static array of 4 pointers to char, initialized to the
4 string-literals that a part of the declaration */
char *array[] = { "The quick",
"brown fox",
"jumps over",
"the lazy dog." };
/* p is a pointer-to-pointer-to-char assigned the address of array */
char **p = array;
/* lines is a pointer-to-pointer-to-char initialized to NULL, used
below to allocate 8 pointers and storage to hold 2 copes of array */
char **lines = NULL;
size_t narray = sizeof array/sizeof *array;
size_t i;
printf ("\nprinting each string-literal at the address stored by\n"
"each pointer in the array of ponters named 'array':\n\n");
for (i = 0; i < narray; i++)
printf (" %s\n", array[i]);
printf ("\nprinting each string using a pointer to pointer to char 'p':\n\n");
for (i = 0; i < narray; i++, p++)
printf (" %s\n", *p);
p = array;
printf ("\nprinting each line using a pointer to pointer"
" to char 'p' with array notation:\n\n");
for (i = 0; i < narray; i++)
printf (" %s\n", p[i]);
/* allocate 8 pointers to char */
lines = malloc (2 * narray * sizeof *lines);
/* allocate memory and copy 1st 4-strings to lines (long way) */
for (i = 0; i < narray; i++) {
size_t len = strlen (array[i]);
lines[i] = malloc (len * sizeof **lines + 1);
strncpy (lines[i], array[i], len);
lines[i][len] = 0;
}
/* allocate memory and copy 1st 4-strings to lines
(using strdup - short way) */
// for (i = 0; i < narray; i++)
// lines[i] = strdup (array[i]);
/* allocate memory and copy again as last 4-strings in lines */
p = array;
for (i = 0; i < narray; i++, p++)
lines[i+4] = strdup (*p);
p = lines; /* p now points to lines instead of array */
printf ("\nprinting each allocated line in 'lines' using pointer 'p':\n\n");
for (i = 0; i < 2 * narray; i++)
printf (" %s\n", p[i]);
/* free allocated memory */
for (i = 0; i < 2 * narray; i++)
free (lines[i]);
free (lines);
return 0;
}
Let me know if you have any questions. It a large topic with a relatively small set of rules that can be applied in whole lot of different ways and in different contexts.
My professor wrote that **array is same as *array[]
That is true in some contexts and not true in other contexts.
If used in a function as argument,
void foo(int **array) {}
is the same as
void foo(int *array[]) {}
When declared as variables,
int **array;
is not the same as
int *array[];
To Explain in short:
if you want to use a pointer to type, you use *array or *ptr, or whatever variable name .
if you want to use an array of pointers and you already know how many pointers you need before execution (for eg. 10 pointers), then you use *array[10] or *ptr[10];
if you want to use an array of pointers but yet you don't know how many pointers you need before execution, then you use **array or **ptr;
after that you can dynamically allocate memory for every pointer using malloc or new operator to allocate memory for whatever data type you are using, (the data type maybe primitive like int, char ,etc, or it maybe user-defined like struct, etc.

Using strdup into malloc reserved space

I've never used malloc to store more than values but I have to use strdup to order the lines of an input file and I dont get a way to make it work.
I though using strdup() to get a pointer to each line and later, put each one into a space according to the number of lines reserved with malloc().
I dont know if I have to do it like reserved memory was an array to pointers, I mean using char** and later put each pointer to each strdup into reserved space.
I though something like this:
char **buffer;
char *pointertostring;
char *line; // line got using fgets
*buffer = (char*)malloc(sizeof(char*));
pointertostring = strdup(line);
I don't know what to do after that, I don't even know if this is correct, in that case, what should I do to store the pointer to the string in a position of buffer?
Regards
If I understand your requirement correctly. You'll have to do something like:
char **buffer;
char line[MAX_LINE_LEN]; // line got using fgets
int count; // to keep track of line number.
// allocate one char pointer for each line in the file.
buffer = (char**)malloc(sizeof(char*) * MAX_LINES);
count = 0; // initilize count.
// iterate till there are lines in the file...read the line using fgets.
while(fgets(line,MAX_LINE_LEN,stdin)) {
// copy the line using strdup and make the buffer pointer number 'count'
// point to it
buffer[count++] = strdup(line);
}
....
....
// once done using the memory you need to free it.
for(count=0;count<MAX_LINES;count++) {
free(buffer[count]);
}
....
....
Your buffer will only hold one pointer. You need something like:
char **buffer;
char *pString;
int linecount;
buffer = (char **)malloc(sizeof(char *)*MAXIMUM_LINES);
linecount = 0;
while (linecount < MAXIMUM_LINES) {
pString = fgets(...);
buffer[linecount++] = strdup(pString);
}

Resources