Dynamic string dimension C based on input - arrays

I want to make a C program that reads a string, but it doesn't require the max length of the array.
I tried this, but it gives me an error:
#include<stdio.h>
int main(){
char a[];
scanf("%s",&a[]);
}
Can I put the length of the array based on the array input, maybe using something like length_of ?

I was about to tell you that it was impossible because you need to have an allocate array to read into it when I realized that C++ extractor could do it (inside a std::string). It is far from trivial and will require that you start with an arbitrary allocated array and realloc it when you need more space.
Here could be a possible code that reads a word of arbitrary size until the first space character (or EOF):
static char* resize(char* buf, size_t* size) {
size_t new_size = *size * 2;
if (new_size <= *size) { // size_t overflow
free(buf);
return NULL;
}
char* newbuf = realloc(buf, *size);
if (!newbuf) {
free(buf);
return NULL;
}
return newbuf;
}
char* getWord(FILE* fd, size_t* size) {
size_t len = 8, cur = 0;
char* buf = malloc(len);
if (!buf) return NULL;
for (;;) {
int c = fgetc(fd);
if (c == EOF || isspace(c)) {
break;
}
if (cur >= len) {
if (!(buf = resize(buf, &len))) {
return NULL;
}
}
buf[cur++] = c;
}
if (cur >= len) {
if (!(buf = resize(buf, &len))) {
return NULL;
}
}
buf[cur] = '\0';
if (size) {
*size = len;
}
return buf;
}
It could be used that way:
int main() {
size_t sz;
char* buf = getWord(stdin, &sz);
printf("%s (%d)\n", buf, sz);
return 0;
}
and when passed exactly 8 characters (abcdefgh), it correctly displays:
abcdefgh (16)
because it allocated one extra position for the terminating null.

Related

How do I dynamically create an array of strings using scanf in C

So I have been searching through stack overflow for a little over an hour and I don't understand why this function is giving me a segmentation error. I want to create a string array, scan strings in through scanf, dynamically change the size of each string and return the string array. Can anyone help? Thank you.
char** readScores(int* count) {
int c = 0;
char** arr =(char**)malloc(100 * sizeof(char*));
char* in;
while(scanf("%s", in) != EOF) {
arr[c] = (char*)malloc(strlen(in)+1);
strcpy(arr[c], in);
}
*count = c;
return arr;
}
char* in;
while(scanf("%s", in) != EOF) {
This tells the computer to read from standard input into the char buffer that in points to.
Which does not exist, because in is not initialised to anything (let alone a valid buffer).
I would not use scanf only fgets.
You need to allocate memory dor the arr and for every line referenced by elements of arr
char** readScores(size_t *count) {
size_t lines = 0;
char** arr = NULL, **tmp;
char* in = malloc(MAXLINE), *result;
size_t len;
if(in)
{
do{
result = fgets(in, MAXLINE, stdin);
if(result)
{
len = strlen(in);
tmp = realloc(arr, sizeof(*tmp) * (lines + 1));
if(tmp)
{
arr = tmp;
len = strlen(in);
arr[lines] = malloc(len + (len == 0));
if(arr[lines])
{
if(len) memcpy(arr[lines], in, len - 1);
arr[lines++][len] = 0;
}
else
{
// error handling
}
}
else
{
// error handling
}
}
}while(result);
free(in);
}
*count = lines;
return arr;
}

Getting valgrind errors with static char * [duplicate]

I have to recode an implementation of the getline() function, but using the file descriptor of the file and not a FILE *. I am only allowed to use malloc() and free(), along with 5 functions being 25 lines long at most.
I think I've done correctly the project although I am a beginner in C and my code isn't probably good.
When I run it, it works fine, but valgrind shows that I definetely lost x bytes, x depending of the file length and the READ_SIZE (macro defined in the header).
According to valgrind's --leak-check=full, I have a memory leak in the str_realloc_cat function, when I malloc dest. I tried but couldn't find where should I free / do something else?
Here below is my code:
char *get_next_line(const int fd)
{
static char *remaining = "";
char *buffer;
ssize_t cread;
size_t i;
i = 0;
if (remaining == NULL)
return (NULL);
if ((buffer = malloc(SOF(char) * READ_SIZE + 1)) == NULL ||
(cread = read(fd, buffer, READ_SIZE)) < 0)
return (NULL);
buffer[cread] = 0;
remaining = str_realloc_cat(remaining, buffer);
while (remaining[i])
{
if (remaining[i] == 10)
{
remaining[i] = 0;
buffer = str_create_cpy(remaining);
remaining = remaining + i + 1;
return (buffer);
}
i++;
}
return (check_eof(fd, buffer, remaining, cread));
}
char *str_realloc_cat(char *rem, char *buf)
{
size_t i;
size_t dest_i;
char *dest;
i = (dest_i = 0);
if ((dest = malloc(SOF(char) * (str_len(rem) + str_len(buf) + 1))) == NULL)
return (NULL);
while (rem[i])
{
dest[dest_i] = rem[i];
dest_i++;
i++;
}
i = 0;
while (buf[i])
{
dest[dest_i] = buf[i];
dest_i++;
i++;
}
dest[dest_i] = 0;
free(buf);
return (dest);
}
char *check_eof(const int fd, char *buffer, char *remaining, ssize_t cread)
{
if (cread == 0)
return (NULL);
if (cread < READ_SIZE)
{
buffer = remaining;
remaining = NULL;
return (buffer);
}
return (get_next_line(fd));
}
char *str_create_cpy(const char *src)
{
char *dest;
size_t i;
i = 0;
if ((dest = malloc(sizeof(char) * str_len(src) + 1)) == NULL)
return (NULL);
while (src[i])
{
dest[i] = src[i];
i++;
}
dest[i] = 0;
return (dest);
}
int str_len(const char *str)
{
size_t i;
i = 0;
while (str[i])
i++;
return (i);
}
And a main functon if you would like to test:
#define SOF(x) sizeof(x) // Why in the comments
int main(int ac, char **av)
{
int fd;
char *s;
UNUSED(ac);
if (!av[1])
return 1;
fd = open(av[1], O_RDONLY);
while ((s = get_next_line(fd)))
{
printf("%s\n", s);
free(s);
}
close(fd);
}
Your algorithm is bad:
You keep the buffer in a allocate memory
You don't use a structure to regroup your variable
You use magic number remaining[i] == 10
You use recursive you can stack overflow return get_next_line(fd). Never mind, I didn't read well you have a tail recursive, just be sure to have the optimization on your compile for it.
You have Spaghetti code.
etc.
You should rewrite your whole function with a better logic first use this structure:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define GNL_SIZE 4096
struct gnl_context {
char buffer[GNL_SIZE];
size_t i;
size_t read;
};
char *get_next_line_r(int fd, struct gnl_context *gnl_context);
char *get_next_line(int fd);
static char *read_buffer(struct gnl_context *gnl_context, char *str,
size_t *size) {
size_t i = gnl_context->i;
while (i < gnl_context->read && gnl_context->buffer[i] != '\n') {
i++;
}
size_t j = i - gnl_context->i;
char *ret = realloc(str, *size + j + 1);
if (ret == NULL) {
return NULL;
}
memcpy(ret + *size, gnl_context->buffer + gnl_context->i, j);
*size += j;
ret[*size] = '\0';
gnl_context->i = i;
return ret;
}
char *get_next_line_r(int fd, struct gnl_context *gnl_context) {
char *str = NULL;
size_t size = 0;
loop:
if (gnl_context->i == gnl_context->read) {
ssize_t ret = read(fd, gnl_context->buffer, GNL_SIZE);
if (ret <= 0) {
return str;
}
gnl_context->read = (size_t)ret;
gnl_context->i = 0;
}
char *tmp = read_buffer(gnl_context, str, &size);
if (tmp == NULL) {
return str;
}
if (gnl_context->i != gnl_context->read) {
gnl_context->i++;
return tmp;
}
str = tmp;
goto loop;
}
char *get_next_line(int fd) {
static struct gnl_context gnl_context;
return get_next_line_r(fd, &gnl_context);
}
int main(void) {
char *str;
while ((str = get_next_line(0)) != NULL) {
printf("%s\n", str);
free(str);
}
}
I am concerned about this line:
remaining = remaining + i + 1;
remaining is a pointer to the allocated buffer. On this line, you destroy it, which means that you cannot free() it anymore.

Coding a getline() implementation - Valgrind errors

I have to recode an implementation of the getline() function, but using the file descriptor of the file and not a FILE *. I am only allowed to use malloc() and free(), along with 5 functions being 25 lines long at most.
I think I've done correctly the project although I am a beginner in C and my code isn't probably good.
When I run it, it works fine, but valgrind shows that I definetely lost x bytes, x depending of the file length and the READ_SIZE (macro defined in the header).
According to valgrind's --leak-check=full, I have a memory leak in the str_realloc_cat function, when I malloc dest. I tried but couldn't find where should I free / do something else?
Here below is my code:
char *get_next_line(const int fd)
{
static char *remaining = "";
char *buffer;
ssize_t cread;
size_t i;
i = 0;
if (remaining == NULL)
return (NULL);
if ((buffer = malloc(SOF(char) * READ_SIZE + 1)) == NULL ||
(cread = read(fd, buffer, READ_SIZE)) < 0)
return (NULL);
buffer[cread] = 0;
remaining = str_realloc_cat(remaining, buffer);
while (remaining[i])
{
if (remaining[i] == 10)
{
remaining[i] = 0;
buffer = str_create_cpy(remaining);
remaining = remaining + i + 1;
return (buffer);
}
i++;
}
return (check_eof(fd, buffer, remaining, cread));
}
char *str_realloc_cat(char *rem, char *buf)
{
size_t i;
size_t dest_i;
char *dest;
i = (dest_i = 0);
if ((dest = malloc(SOF(char) * (str_len(rem) + str_len(buf) + 1))) == NULL)
return (NULL);
while (rem[i])
{
dest[dest_i] = rem[i];
dest_i++;
i++;
}
i = 0;
while (buf[i])
{
dest[dest_i] = buf[i];
dest_i++;
i++;
}
dest[dest_i] = 0;
free(buf);
return (dest);
}
char *check_eof(const int fd, char *buffer, char *remaining, ssize_t cread)
{
if (cread == 0)
return (NULL);
if (cread < READ_SIZE)
{
buffer = remaining;
remaining = NULL;
return (buffer);
}
return (get_next_line(fd));
}
char *str_create_cpy(const char *src)
{
char *dest;
size_t i;
i = 0;
if ((dest = malloc(sizeof(char) * str_len(src) + 1)) == NULL)
return (NULL);
while (src[i])
{
dest[i] = src[i];
i++;
}
dest[i] = 0;
return (dest);
}
int str_len(const char *str)
{
size_t i;
i = 0;
while (str[i])
i++;
return (i);
}
And a main functon if you would like to test:
#define SOF(x) sizeof(x) // Why in the comments
int main(int ac, char **av)
{
int fd;
char *s;
UNUSED(ac);
if (!av[1])
return 1;
fd = open(av[1], O_RDONLY);
while ((s = get_next_line(fd)))
{
printf("%s\n", s);
free(s);
}
close(fd);
}
Your algorithm is bad:
You keep the buffer in a allocate memory
You don't use a structure to regroup your variable
You use magic number remaining[i] == 10
You use recursive you can stack overflow return get_next_line(fd). Never mind, I didn't read well you have a tail recursive, just be sure to have the optimization on your compile for it.
You have Spaghetti code.
etc.
You should rewrite your whole function with a better logic first use this structure:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define GNL_SIZE 4096
struct gnl_context {
char buffer[GNL_SIZE];
size_t i;
size_t read;
};
char *get_next_line_r(int fd, struct gnl_context *gnl_context);
char *get_next_line(int fd);
static char *read_buffer(struct gnl_context *gnl_context, char *str,
size_t *size) {
size_t i = gnl_context->i;
while (i < gnl_context->read && gnl_context->buffer[i] != '\n') {
i++;
}
size_t j = i - gnl_context->i;
char *ret = realloc(str, *size + j + 1);
if (ret == NULL) {
return NULL;
}
memcpy(ret + *size, gnl_context->buffer + gnl_context->i, j);
*size += j;
ret[*size] = '\0';
gnl_context->i = i;
return ret;
}
char *get_next_line_r(int fd, struct gnl_context *gnl_context) {
char *str = NULL;
size_t size = 0;
loop:
if (gnl_context->i == gnl_context->read) {
ssize_t ret = read(fd, gnl_context->buffer, GNL_SIZE);
if (ret <= 0) {
return str;
}
gnl_context->read = (size_t)ret;
gnl_context->i = 0;
}
char *tmp = read_buffer(gnl_context, str, &size);
if (tmp == NULL) {
return str;
}
if (gnl_context->i != gnl_context->read) {
gnl_context->i++;
return tmp;
}
str = tmp;
goto loop;
}
char *get_next_line(int fd) {
static struct gnl_context gnl_context;
return get_next_line_r(fd, &gnl_context);
}
int main(void) {
char *str;
while ((str = get_next_line(0)) != NULL) {
printf("%s\n", str);
free(str);
}
}
I am concerned about this line:
remaining = remaining + i + 1;
remaining is a pointer to the allocated buffer. On this line, you destroy it, which means that you cannot free() it anymore.

How to malloc for getline implementation

I'm trying to add getline support to http-fs-wrapper and I have some malloc problems.
ssize_t _intercept_getdelim(int fd, char **lineptr, size_t *n, int delim)
{
intercept_t *obj = intercept[fd];
int counter;
size_t nc = sizeof(char);
counter = -1;
while (obj->offset < obj->size)
{
++counter;
if (*lineptr) {
*lineptr = realloc(*lineptr, (counter + 2) * nc);
}
else {
*lineptr = malloc(nc);
}
_intercept_read(fd, lineptr[counter], nc);
if (*lineptr[counter] == delim)
{
break;
}
}
*n = counter ? counter + 1 : counter;
*lineptr[counter + 2] = '\0';
// Why do we need a *n when the return value is the same??
return *n;
}
Here's the relevant section of _intercept_read:
size_t _intercept_read(int fd, void *buf, size_t count)
{
memcpy(buf, obj->ra_buf+bo, count);
When I step through this in gdb, the second iteration throws a SIGSEGV (from memcpy -- it's not the ending \0, it's still inside the loop). I also don't quite get what's the difference between the *n of getline/getdelim and the return value.
The difference between n and the return value is that n is always the buffer size, but the return value can be -1 for error states per posix spec. You aren't fully handling EOF (it should return -1 if it hits EOF and hasn't read anything yet).
A note, reallocing for every character is fairly inefficient. The standard pattern is to double the buffer size each time it is necessary. This is another way the return value and n can differ, since n is the buffer size, which can be much larger than the read character count it returns.
You also don't need to special case a starting null pointer, realloc internally calls malloc in that case.
buf = realloc(buf...) is an unsafe pattern, realloc can return null, you have to save the realloc result to a temp variable and check it before assigning, otherwise you both leak memory and can reference a null pointer.
I don't think there's actually space for the trailing null you're adding to the buffer at the end there.
This works:
ssize_t _intercept_getdelim(int fd, char **lineptr, size_t *n, int delim)
{
intercept_t *obj = intercept[fd];
int counter = -1;
char *c, *newbuf;
*n = 1;
*lineptr = malloc(*n);
while (obj->offset < obj->size)
{
++counter;
if (counter >= *n)
{
if ((newbuf = realloc(*lineptr, *n << 1)))
{
*n = *n << 1;
*lineptr = newbuf;
}
else
{
return -1;
}
}
c = *lineptr + counter;
_intercept_read(fd, c, nc);
if (*c == delim)
{
break;
}
}
if (counter > -1)
{
*(*lineptr + ++counter) = '\0';
}
return counter;
}

to store char* from function return value

I am trying to implement a function which reads from Serial Port ( Linux) and retuns char*.
The function works fine but how would I store return value from function.
example of function is
char *ReadToSerialPort()
{
char *bufptr;
char buffer[256]; // Input buffer/ /
//char *bufptr; // Current char in buffer //
int nbytes; // Number of bytes read //
bufptr = buffer;
while ((nbytes = read(fd, bufptr, buffer+sizeof(buffer)-bufptr -1 )) > 0)
{
bufptr += nbytes;
// if (bufptr[-1] == '\n' || bufptr[-1] == '\r')
/*if ( bufptr[sizeof(buffer) -1] == '*' && bufptr[0] == '$' )
{
break;
}*/
} // while ends
if ( nbytes ) return bufptr;
else return 0;
*bufptr = '\0';
} // end ReadAdrPort
//In main
int main( int argc , char *argv[])
{
char *letter;
if(strcpy(letter, ReadToSerialPort()) >0 )
{
printf("Response is %s\n",letter);
}
}
You should allocate a buffer at heap with malloc, and return it. The users of your function will be responsible for deallocating the memory (and your documentation has to clearly state this!)
A simple change would be
char* buffer = (char*)malloc(256);
// beware that now `sizeof(buffer)` will be not 256 any more, but 4, so
// you have to define your constant for it.
...
if (nbytes) return buffer;
free(buffer);
return 0;
...
int main(int argc, char *argv[])
{
char *letter = ReadToSerialPort();
if (letter)
{
printf("Response is %s\n", letter);
free(letter);
return 0;
}
return 1;
}
Please note that the code *bufptr = '\0'; should be before return, not after!
EDIT
Does your code look like this:
char *ReadToSerialPort()
{
const int buffer_size = 256;
char *buffer = (char *)malloc(buffer_size);
char *bufptr = buffer;
int nbytes;
while ((nbytes = read(fd, bufptr, buffer+buffer_size-bufptr-1)) > 0)
{
bufptr += nbytes;
}
*bufptr = '\0';
if (bufptr != buffer)
return bufptr;
// else cleaning up
free(buffer);
return 0;
}
I am curious where does fd come from?
Fix up your main code to look like this:
//In main
int main( int argc , char *argv[])
{
char *letter = ReadToSerialPort();
if(letter != NULL)
{
printf("Response is %s\n",letter);
}
}
Make sure you use the buffer declared as static within ReadToSerialPort().....
i.e.:
static char buffer[256];
You need to specify your function a bit more. You can not simply say it "returns a char *". Where are the characters it points to? In a static buffer? On the heap (allocated by new)? It looks like you are trying to return a pointer to a local buffer (allocated on the stack), which is an error. Alternatively, return a std::string.
You should change the signature of ReadToSerialPort() to also inform the caller how many bytes you are returning. So you could do either this:
int ReadToSerialPort(char** data);
or this:
void ReadToSerialPort(char** data, int* num_of_bytes);
and you stay responsible for allocating memory space inside ReadToSerialPort().
The user would do something like (not tested):
int main( int argc , char *argv[])
{
char* data = NULL;
int count = 0;
ReadToSerialPort(data, &count);
if (data != NULL && count > 0) // Let's suppose count returns as 5
{
printf("data[0]:%x data[1]:%x data[2]:%x data[3]:%x data[4]:%x\n", data[0], data[1], data[2], data[3], data[4]);
}
// and the user is responsible for deallocating data himself
free(data);
return 0;
}

Resources