How to properly access this realloc-ed array? - c

In this code below I am trying to create an array of ints that can be accessed from the main() function, however, Address-sanitizer gives me stack-buffer-overflow-error and I cannot figure out what I am doing wrong. What am I missing?
#include <stdlib.h>
void reallocFail(int **arrayOfInts) {
*arrayOfInts = (int *)malloc(sizeof(int));
for (int i = 1; i <= 10; i++) {
*arrayOfInts = (int *)realloc(*arrayOfInts, (i) * sizeof(int));
*arrayOfInts[i - 1] = i;
}
}
int main(void) {
int *arrayOfInts;
reallocFail(&arrayOfInts);
return 0;
}

There is just a simple typo in *arrayOfInts[i - 1] = i;. suffix operators such as [] bind stronger than prefix operators such as *. Hence you should write:
(*arrayOfInts)[i - 1] = i;
Note also that you should check for memory reallocation failure and you can initialize *arrayOfInts to NULL as realloc(NULL, size) is equivalent to malloc(size).
Here is a modified version:
#include <string.h>
#include <stdlib.h>
int reallocFail(int **pp, int n) {
int i;
*pp = NULL;
for (i = 0; i < n; i++) {
int *p = realloc(*pp, (i + 1) * sizeof(*p));
if (p == NULL)
break;
p[i] = i + 1;
*pp = p;
}
return i;
}
int main(void) {
int *arrayOfInts = NULL;
int n = reallocFail(&arrayOfInts, 10);
for (int i = 0; i < n; i++) {
printf("%d%c", arrayOfInts[i], " \n"[i == n-1]);
}
free(arrayOfInt);
return 0;
}

void reallocFail(int **arrayOfInts)
{
for (int i = 1; i <= 10; i++)
{
*arrayOfInts = realloc(*arrayOfInts, i * sizeof(**arrayOfInts));
arrayOfInts[0][i - 1] = i;
}
}
int main(void) {
int *arrayOfInts = NULL;
reallocFail(&arrayOfInts);
return 0;
}
But this code can be reduced to one realloc (I understand that you test if realloc works).
IT does not check if the realloc has succeeded or failed:
void reallocFail(int **arrayOfInts)
{
int *tmp;
for (int i = 1; i <= 10; i++)
{
tmp = realloc(*arrayOfInts, i * sizeof(**arrayOfInts));
if(tmp)
{
*arrayOfInts = tmp;
arrayOfInts[0][i - 1] = i;
}
else
printf("Alloction error\n");
}
}

For starters this memory allocation before the for loop
*arrayOfInts = (int*)malloc(sizeof(int));
is redundant. You could just write
*arrayOfInts = NULL;
Also you need to check whether memory allocation was successful.
Also this record
*arrayOfInts[i-1] = i;
is equivalent to
*( arrayOfInts[i-1] ) = i;
but you need
( *arrayOfInts )[i-1] = i;
The function can look the following way
size_t reallocFail( int **arrayOfInts, size_t n )
{
*arrayOfInts = NULL;
size_t i = 0;
if ( n != 0 )
{
int *tmp = NULL;
do
{
tmp = realloc( *arrayOfInts, ( i + 1 ) * sizeof( int ) );
if ( tmp != NULL )
{
tmp[i] = i + 1;
*arrayOfInts = tmp;
}
} while ( tmp != NULL && ++i != n );
}
return i;
}
And the function can be called for example like
int *arrayOfInts = NULL;
size_t n = reallocFail( &arrayOfInts, 10 );
for ( size_t i = 0; i != n; i++ )
{
printf( "%d ", arrayOfInts[i] );
}
putchar( '\n' );
free( arrayOfInts );
Here is a demonstration program.
#include <stdio.h>
#include <stdlib.h>
size_t reallocFail( int **arrayOfInts, size_t n )
{
*arrayOfInts = NULL;
size_t i = 0;
if ( n != 0 )
{
int *tmp = NULL;
do
{
tmp = realloc( *arrayOfInts, ( i + 1 ) * sizeof( int ) );
if ( tmp != NULL )
{
tmp[i] = i + 1;
*arrayOfInts = tmp;
}
} while ( tmp != NULL && ++i != n );
}
return i;
}
int main( void )
{
int *arrayOfInts = NULL;
size_t n = reallocFail( &arrayOfInts, 10 );
for ( size_t i = 0; i != n; i++ )
{
printf( "%d ", arrayOfInts[i] );
}
putchar( '\n' );
free( arrayOfInts );
return 0;
}
The program output is
1 2 3 4 5 6 7 8 9 10
Of course there is no great sense to reallocate the memory in the loop within the function. The function just demonstrates how to manage the function realloc.

Related

adding zeros before string

zfill algorithm is supposed to work as follows:
zfill function accepts two parameters, a string and a number,
if string length is >= the number, then it doesn't have to add anything, and it returns a copy to the string,
else, malloc enough space and add zeros before the string.
I'm trying to understand why is this solution not correct, it has two warnings:
1st warning:
for (i; i < zeros; i++) {
s[i] = "0";
}
"=": char differs in level of indirection from char[2]
2nd warning:
for (i; i < n; i++) {
s[i] = str[i];
}
buffer overrun while writing to s
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = "0";
}
for (i; i < n; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
return s;
}
int main(void) {
char str[] = "hello, world!";
size_t n = 40;
char* s = zfill(str, n);
free(s);
return 0;
}
EDIT: I've solved the problem this way:
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum-1] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = '0';
}
for (size_t j = 0; i < n; j++) {
s[i++] = str[j];
}
s[sum-1] = 0;
}
return s;
}
and it works, but I don't know why I have this warning:
for (i; i < zeros; i++) {}
statement with no effect
but when I've debugged I've noticed that this statement has an effect, because it correctly copies the correct number of zeros. I don't know why I have this warning
SO is a place of learning.
When first dealing with a coding challenge, it's best to take time to work out what's needed before starting to write code.
Below is a working version of zfill() (along with a main() that tests it.)
Read through the comments. The only thing new here is memset().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// A trivial "helper function" determines the max of two values
int max( int a, int b ) { return a > b ? a : b; }
char *zfill( char *str, int minLen ) {
// Determine length of arbitrary string
int len = strlen( str );
// Determine max of length v. minimum desired
int allocSize = max( minLen, len );
// allocate buffer to store resulting string (with '\0')
char *obuf = (char*)malloc( allocSize + 1 );
/* omitting test for failure */
// determine start location at which to copy str
int loc = len <= minLen ? minLen - len : 0;
if( loc > 0 )
// fill buffer with enough 'zeros'
memset( obuf, '0', allocSize ); // ASCII zero!
// copy str to that location in buffer
strcpy( obuf + loc, str );
// return buffer to calling function
return obuf;
}
int main() {
// collection of strings of arbitrary length
char *strs[] = { "abc", "abcdefghijkl", "abcde", "a", "" };
// pass each one to zfill, print, then free the alloc'd buffer.
for( int i = 0; i < sizeof strs/sizeof strs[0]; i++ ) {
char *cp = zfill( strs[i], 10 );
puts( cp );
free( cp );
}
return 0;
}
Output:
0000000abc
abcdefghijkl
00000abcde
000000000a
0000000000
Here's zfill() without the comments:
char *zfill( char *str, int minLen ) {
int len = strlen( str );
int allocSize = max( minLen, len );
char *obuf = (char*)malloc( allocSize + 1 );
/* omitting test for failure */
int loc = len <= minLen ? minLen - len : 0;
if( loc > 0 )
memset( obuf, '0', loc ); // ASCII zero!
strcpy( obuf + loc, str );
return obuf;
}
You don't want to spend your time staring at lines and lines of code.
Fill your quiver with arrows that are (proven!) standard library functions and use them.
I've omitted, too, the test for zfill being passed a NULL pointer.
This code snippet
size_t sum = length + 1u;
s = malloc(sum);
//...
s[sum] = 0;
accesses memory outside the allocated character array because the valid range of indices is [0, sum). You need to write at least like
s[length] = 0;
In this code snippet
for (i; i < zeros; ++) {
s[i] = "0";
}
the expression s[i] represents a single object of the type char while on the right-hand side there is a string literal that as an expression has the type char *. You need to write at least
s[i] = '0';
using the integer character constant instead of the string literal.
In this code snippet
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = "0";
}
for (i; i < n; i++) {
s[i] = str[i];
}
as the length of the string str can be less than n then this for loop
for (i; i < n; i++) {
s[i] = str[i];
}
accesses memory outside the string str.
Pay attention to that your function has redundant code. It can be written simpler.
The function can look for example the following way as shown in the demonstration program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * zfill( const char *s, size_t n )
{
char *result = NULL;
if ( s != NULL )
{
size_t len = strlen( s );
n = len < n ? n : len;
result = malloc( n + 1 );
if ( result )
{
size_t i = 0;
size_t m = len < n ? n - len : 0;
for ( ; i < m; i++ )
{
result[i] = '0';
}
for ( ; i < n; i++ )
{
result[i] = s[i - m];
}
result[i] = '\0';
}
}
return result;
}
int main( void )
{
const char *s = "Hello";
size_t n = 10;
char *result = zfill( s, n );
if ( result ) puts( result );
free( result );
}
The program output is
00000Hello
Or as #Some programmer dude pointed to in his comment you can use the standard C function snprintf that alone performs the task. For example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * zfill( const char *s, size_t n )
{
char *result = NULL;
if ( s != NULL )
{
size_t len = strlen( s );
n = len < n ? n : len;
result = malloc( n + 1 );
if ( result )
{
int m = len < n ? n - len : 0;
snprintf( result, n + 1, "%.*d%s", m, 0, s );
}
}
return result;
}
int main( void )
{
char *p = zfill( "Hello", 5 );
if ( p ) puts( p );
free( p );
p = zfill( "Hello", 10 );
if ( p ) puts( p );
free( p );
}
The program output is
Hello
00000Hello
so you have 3 major problems in your code :
it's s[i] = '0'; not s[i] = "0";
it's s[i] = str[i - zeros]; not s[i] = str[i]; as the value of the i will be 27 in your test case : so it make sense to say s[27] because its size is about 41 but it doesn't make sense to say str[27] as its size is only about 13 in your test case , so you had to map the value 27 of i to the value 0 to be convenient to use with str
i is deprecated in first part here for (i; i < zeros; i++) , so use for (; i < zeros; i++)instead of for (i; i < zeros; i++) , but it will not cause any problem if you keep it.
and here is the full edited code :
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (; i < zeros; i++) {
s[i] = '0';
}
for (; i < n; i++) {
s[i] = str[i - zeros];
}
s[sum] = 0;
}
return s;
}
int main(void) {
char str[] = "hello, world!";
size_t n = 40;
char* s = zfill(str, n);
printf("%s\n", s);
free(s);
return 0;
}

I want to create my own tail command with using getline and wihout use of lseek and fseek

I implemented below code but i want tailbuf[] should be in order. I want tailbuf[9] should be last line, tailbuf[8] second and so on. Please help me how i cant implement that in this code.
#include<stdio.h>
#include<stdlib.h>
char ** lastnumlines(FILE *fp, unsigned int num)
{
int count = num;
int n, i, iNo1 = 0, iNo2= 0,z = 0;
size_t MAXSIZE = 1024;
char **tailbuf=calloc(count, sizeof(char *));
for (i = 0; i < count; i++)
{
tailbuf[i] = calloc(MAXSIZE, sizeof(char));
}
while (getline(&tailbuf[iNo2], &MAXSIZE, fp) != EOF)
{
iNo2 = (iNo2 + 1) % count;
if (iNo2 == iNo1)
{
iNo1 = (iNo1 + 1) % count;
}
}
i = iNo2;
int k = 0;
do{
printf("%s\n",tailbuf[i]);
i = (i+1) % count;
}while (i != iNo2);
free(tailbuf);
}
int main()
{
char *filename = "demo1.txt";
FILE *fp = fopen(filename,"r");
if(fp == NULL)
{
printf("Unable to open file!\n");
exit(1);
}
lastnumlines(fp,10);
fclose(fp);
return 0;
}
How i can tailbuf in order?
A simple solution should be to have two arrays of lines pointers (note that the memory won't be duplicated)
a circular buffer to read the file without other difficulty than using a mod op %
a linear buffer reordering the read line to be used elsewhere:
void lastnumlines(FILE *fp, unsigned int num)
{
/* variable names have been made more expressive */
int i;
size_t size = 1024;
char **tailbuf=calloc(num, sizeof(char *));
char **circbuf=calloc(num, sizeof(char *));
int index_in_buff = 0;
int line_no = 0;
for (i = 0; i < num; ++i) {
circbuf[i] = malloc(size);
}
/* get lines in circular buffer */
while (getline(&circbuf[index_in_buff % num], &size, fp) != EOF)
{
++index_in_buff;
++line_no;
}
/* reorder lines from circular to linear buffer */
for (i = 0; i < num; ++i) {
printf("%d --> %d\n", (line_no+i)%num, i);
tailbuf[i] = circbuf[(line_no+i)%num];
}
/* display lines, warning, some may be null if num > line_no */
for (i = 0; i < num; ++i) {
if (tailbuf[i])
printf("%s", tailbuf[i]);
}
/* cleanup memory */
for (i = 0; i < num; ++i) {
free(tailbuf[i]);
}
free(tailbuf);
free(circbuf);
}
Note that the circbuf can be deleted at the end of function, and tailbuf can be returned to be used in other functions. Both tailbuf and circbuf point to line memory, but there is no deep bind.
Here's a sketch of how you could do this with a single array of pointers.
Up to 10 lines populate pArr pointers, then memmove will "scroll-up" the array so that the 'next' read is always to the final pointer.
const int n = 10; // Want last 10 lines. (fewer if short input).
char *pArr[ n ];
for( int i = 0; i < n; i++ )
pArr[ i ] = calloc( 128, sizeof(char) );
int lcnt = 0, retCode = 0;
while( retCode != EOF ) {
if( lcnt == n - 1 ) {
char *hold = pArr[0];
memmove( pArr, pArr + 1, (n - 1) * sizeof(pArr[0]) );
pArr[ lcnt ] = hold;
}
retCode = getline( pArr[ lcnt ], size, fp );
if( ++lcnt == n )
lcnt--;
}
for( i = 0; i <= lcnt; i++ )
printf( ... );
for( i = 0; i < n; i++ )
free( pArr[ i ] );

number characters from input

bool in_array(char a[], char input, int len){
for (int l = 0; l < len; l++){
}
}
return false;
}
int main(void) {
char i = 'l';
int count = 0;
int count_d = 0;
char a[1000] = {0};
else{
count_d++;
}
}
printf("%d\n", count_d);
}
this is the code i have but this returns numbers of times it has duplicated
as there are two characters a and b
If you have learnt only arrays and do not know how to allocate memory dynamically then use a second array to store unique duplicated characters.
Here is a demonstrative program.
#include <stdio.h>
#include <stdbool.h>
bool in_array( const char a[], size_t n, char c )
{
size_t i = 0;
while ( i != n && a[i] != c ) i++;
return i != n;
}
int main(void)
{
enum { N = 128 };
char a[N];
char b[N / 2];
size_t count_duplicates = 0;
size_t count = 0;
char c;
while ( count < N && scanf( " %c", &c ) == 1 )
{
if ( !in_array( a, count, c ) )
{
a[count++] = c;
}
else if ( !in_array( b, count_duplicates, c ) )
{
b[count_duplicates++] = c;
}
}
printf( "There are %zu duplicated character(s).\n", count_duplicates );
return 0;
}
If to enter the sequence of characters
aaabbaaac
then the program output will be
There are 2 duplicated character(s).
i hope it will help you :
`#include <unistd.h>
#include <stdio.h>
#include <string.h>
int in_a(char *a, char c)
{
for (int i = 0; i < strlen(a); i++)
if (a[i] == c)
return 0;
return (1);
}
int main(int ac, char **av)
{
int count_duplicates = 0;
int same = 0;
char old = 0;
char new[128] = {0}; // i
int count = 0;
char *a = av[1];
while (a[count] != '\0') {
if (old != a[count] && in_a(new, a[count])) {
same = 0;
}
if (a[count] == old && same != 1) {
count_duplicates += 1;
same = 1;
}
old = a[count];
new[count] = a[count];
count += 1;
}
printf("%i\n", count_duplicates);
return (0);
}`

How modify a multidimensional pointer inside a function?

I have a function that manipulates a char*** using malloc and memcpy this way
// Convert a buffer full line to separated variables
int parseBufferToVariables(char ***variableContainer, char *bufferToParse, int maxVarSize) {
int i = 0;
// Get number of rows of the string
int numberOfRows = 0;
for (i = 0; bufferToParse[i] != '\0'; i++) {
if (bufferToParse[i] == '\n')
++numberOfRows;
}
// Get number of columns of the string
int numberOfColumns = 1;
for (i = 0; bufferToParse[i] != '\n'; i++) {
if (bufferToParse[i] == '\t')
++numberOfColumns;
}
// Allocate separated variable array
size_t dim0 = numberOfColumns, dim1 = numberOfRows, dim2 = maxVarSize;
variableContainer = malloc(sizeof *variableContainer * dim0);
if (variableContainer) {
size_t i;
for (i = 0; i < dim0; i++) {
variableContainer[i] = malloc(sizeof *variableContainer[i] * dim1);
if (variableContainer[i]) {
size_t j;
for (j = 0; j < dim1; j++) {
variableContainer[i][j] = malloc(sizeof *variableContainer[i][j] * dim2);
}
}
}
}
// Start parsing string to 3D array
int init = 0;
int numberOfVars = 0;
int numberOfLines = 0;
int sizeOfVar = 0;
int position = 0;
char emptyArray[MAXVARSIZE] = {0};
// Loop trought all lines
i = 0;
while (numberOfLines < numberOfRows) {
// Every delimiter
if (bufferToParse[i] == '\t' || bufferToParse[i] == '\n') {
// Size of the new sring
sizeOfVar = i - init;
// Set last \0 character in order to recognize as a proper string
memcpy(&variableContainer[numberOfVars][numberOfLines], emptyArray, maxVarSize);
// Copy the string to array
memcpy(&variableContainer[numberOfVars][numberOfLines], &bufferToParse[position], sizeOfVar);
// Handle pointers poisition
init = i + 1;
position += sizeOfVar + 1;
// Handle when end of line is reached
if (bufferToParse[i] == '\n') {
numberOfVars = 0;
numberOfLines++;
}
}
i++;
}
return numberOfRows;
}
And Im trying to call it in different ways:
char*** container= {0};
parseBufferToVariables (&container, inputString, MAXVARSIZE);
char*** container= {0};
parseBufferToVariables (container, inputString, MAXVARSIZE);
Even I try calling a char**** in the function:
int parseBufferToVariables(char**** variableContainer, char* bufferToParse, int maxVarSize)
But I always have a seg-fault calling the char*** outside the parseBufferToVariables function.
Any ideas?
OP is shooting for a 4 * parameter, yet other approaches are better.
The high degree of *s mask a key failing is that code needs to convey the column (# of tabs) width somehow.
Further, I see no certain null character termination in forming the _strings_as
the 2nd memcpy() is unbounded in size - may even overwrite allocation boundaries.
The idea below is that each level of allocation ends with a null.
csv = parse_file_string(const char *file_string);
Upon return, when csv[line] == NULL, there are no more lines
When csv[line][tab] == NULL, there are no more strings.
This approach also allows for a different number of strings per line.
Adjusted algorithm, pseudo C code
// return NULL on error
char ***parse_file_string(const char *file_string) {
number_lines = find_line_count(file_string);
char ***csv = calloc(number_lines + 1, sizeof *csv);
if (csv == NULL) return NULL;
for (line=0; line < number_lines; line++) {
tab_count = find_tab_count(file_string);
csv[line] = calloc(tab_count + 2, sizeof *(csv[line]));
// add NULL check
for (tab=0; tab < tab_count; tab++) {
char *end = strchr(file_string, '\t');
csv[line][tab] = malloc_string(file_string, end);
// add NULL check
file_string = end + 1;
}
char *end = strchr(file_string, '\n');
csv[line][tab++] = malloc_str(file_string, end);
// add NULL check
file_string = end + 1;
csv[line][tab] = NULL;
}
csv[line] = NULL;
return csv;
}
Usage
char ***container = parse_file_string(file_string);
for (line=0; container[line]; line++)
for (tab=0; container[line][tab]; tab++)
puts(container[line][tab]);
//free
for (line=0; container[line]; line++)
for (tab=0; container[line][tab]; tab++)
free(container[line][tab]);
free(container[line]);
free (container)
A pointer to a variable length array could be used if supported.
First get the dimensions of the contents of the buffer. This assumes that each line will have the same number of tabs.
Declare the pointer and allocate the memory.
Then parse the buffer into the allocated memory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getdimension ( char *buffer, int *rows, int *cols, int *size) {
int maxsize = 0;
*rows = 0;
*cols = 0;
*size = 0;
while ( *buffer) {//not the terminating zero
if ( '\n' == *buffer) {
if ( ! *rows) {//no rows counted yet
++*cols;//add a column
}
++*rows;
if ( maxsize > *size) {
*size = maxsize;
}
maxsize = 0;
}
if ( '\t' == *buffer) {
if ( ! *rows) {//no rows counted yet
++*cols;
}
if ( maxsize > *size) {
*size = maxsize;
}
maxsize = 0;
}
++maxsize;
++buffer;
}
if ( '\n' != *(buffer - 1)) {//last character is not a newline
++*rows;
if ( maxsize > *size) {
*size = maxsize;
}
}
}
void createptr ( int rows, int columns, int size, char (**ptr)[columns][size]) {
if ( NULL == ( *ptr = malloc ( sizeof **ptr * rows))) {
fprintf ( stderr, "malloc problem\n");
exit ( EXIT_FAILURE);
}
for ( int line = 0; line < rows; ++line) {
for ( int tab = 0; tab < columns; ++tab) {
(*ptr)[line][tab][0] = 0;
}
}
}
void parsebuffer ( char *buffer, int rows, int columns, int size, char (*ptr)[columns][size]) {
int eachrow = 0;
int eachcol = 0;
int eachsize = 0;
while ( *buffer) {
if ( '\n' == *buffer) {
++eachrow;
eachcol = 0;
eachsize = 0;
}
else if ( '\t' == *buffer) {
++eachcol;
eachsize = 0;
}
else {
ptr[eachrow][eachcol][eachsize] = *buffer;
++eachsize;
ptr[eachrow][eachcol][eachsize] = 0;
}
++buffer;
}
}
int main ( void) {
char line[] = "12\t34\t56\t78\t!##\n"
"abc\tdef\tghi\tjkl\t$%^\n"
"mno\tpqr\tstu\tvwx\tyz\n"
"ABC\tDEF\tGHI\tJKL\tMNOPQ\n";
int rows = 0;
int columns = 0;
int size = 0;
getdimension ( line, &rows, &columns, &size);
printf ( "rows %d cols %d size %d\n", rows, columns, size);
char (*ptr)[columns][size] = NULL;//pointer to variable length array
createptr ( rows, columns, size, &ptr);
parsebuffer ( line, rows, columns, size, ptr);
for ( int row = 0; row < rows; ++row) {
for ( int col = 0; col < columns; ++col) {
printf ( "ptr[%d][%d] %s\n", row, col, ptr[row][col]);
}
}
free ( ptr);
return 0;
}

How to dynamic malloc memory in function in c?

I want to call a function like this:
char* Seg(char* input, char **segs, int* tags)
in fact input is the real input, segs tags is the return, and now return is the error message.
my program like this:
#include <stdio.h>
char* Seg(char* input, char **segs, int* tags) {
// dynamic malloc the memory here
int count = strlen(input); // this count is according to input
for (int i = 0; i < count; i++) {
segs[i] = "abc";
}
for (int i = 0; i < count; i++) {
tags[i] = i;
}
return NULL;
}
int main(int argc, char *argv[])
{
char** segs = NULL;
int* tags = NULL;
Seg("input", segs, tags);
return 0;
}
I am asking how can I return the value in segs and tags?
Edit
Now I change code to this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* input is input params, segs and tags is results
* return: error msg
*/
int Seg(char* input, char ***segs, int** tags) {
int n = strlen(input);
int *tags_ = malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
tags_[i] = i;
}
tags = &tags_;
char **segs_ = malloc(sizeof(char *) * n);
for (int i = 0; i < n; i++) {
segs_[i] = "haha";
}
segs = &segs_;
return n;
}
int main(int argc, char *argv[])
{
char** segs = NULL;
int* tags = NULL;
int n = Seg("hahahahah", &segs, &tags);
printf("%p", tags);
free(segs);
free(tags);
return 0;
}
Why tags is still nil?
If I have understood you correctly then you need something like the following.
I used sentinel values for the both dynamically allocated arrays. You can use your own approach instead of using sentinel values.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * Seg( const char *input, char ***segs, int **tags )
{
// dynamic malloc the memory here
size_t count = strlen( input ); // this count is according to input
*segs = malloc((count + 1) * sizeof(char *));
*tags = malloc((count + 1) * sizeof(int));
for ( size_t i = 0; i < count; i++ )
{
( *segs )[i] = "abc";
}
(*segs)[count] = NULL;
for ( size_t i = 0; i < count; i++ )
{
( *tags )[i] = ( int )i;
}
(*tags)[count] = -1;
return NULL;
}
int main( void )
{
char **segs = NULL;
int *tags = NULL;
Seg( "input", &segs, &tags );
for (char **p = segs; *p; ++p)
{
printf( "%s ", *p );
}
putchar('\n');
for (int *p = tags; *p != -1; ++p)
{
printf("%d ", *p);
}
putchar('\n');
free(segs);
free(tags);
return 0;
}
The program output is
abc abc abc abc abc
0 1 2 3 4
After you updated your post then the function can look also the following way
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t Seg( const char *input, char ***segs, int **tags )
{
// dynamic malloc the memory here
size_t count = strlen( input ); // this count is according to input
*segs = malloc(count * sizeof(char *));
*tags = malloc(count * sizeof(int));
for ( size_t i = 0; i < count; i++ )
{
( *segs )[i] = "abc";
}
for ( size_t i = 0; i < count; i++ )
{
( *tags )[i] = ( int )i;
}
return count;
}
int main( void )
{
char **segs = NULL;
int *tags = NULL;
size_t n = Seg( "input", &segs, &tags );
for (size_t i = 0; i < n; i++)
{
printf( "%s ", segs[i] );
}
putchar('\n');
for (size_t i = 0; i < n; i++)
{
printf("%d ", tags[i]);
}
putchar('\n');
free(segs);
free(tags);
return 0;
}
You can also add code to the function that checks whether the memory was allocated successfully.
As for your additional question then such a code like for example this
int *tags_ = malloc(n * sizeof(int));
tags = &tags_;
changes local variable tags of the type int ** (function parameters are function local variables) instead of changing the original pointer tags of the type int * passed to the function by reference as an argument.

Resources