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
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;
}
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.
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.
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;
}
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;
}