read function: copying buffer to another char array - c

I'm new to C and am trying to use the read function. I want to take what's in the buffer (tempChar) and put it in another char array (str). This is so I can run the read function again and add on to str later (because tempChar will be rewritten by the 2nd read function). Like this:
char tempChar;
read(0, &tempChar, 10);
char *str;
str= (char*) malloc(10);
memcpy(str, &tempChar, fileSize); /*I'm doing something wrong here*/
All this so I can rerun:
read(0,&tempChar, 1);
str= realloc(str, 11);
str[10]=tempChar;
It compiles fine, but it gives me a segmentation fault when I actually try to run it.
Any ideas? Thanks a bunch.

you need to have enough storage to store the 10 characters you are reading
you declared
char tempChar
which can hold 1 character.
Instead declare tempChar as
char tempChar[10];

char tempChar;
read(0, &tempChar, 10);
You are reading 10 characters from the file into memory only the size of a single char.
char tempChar only reserves memory for a single character, &tempChar points to this single byte of memory.
char *str;
str= (char*) malloc(10);
// why not now do ?
read(0, str, 10);

char tempChar;
Only allocates 1 byte. So you can only hold there 1 char. When you memcpy() you request to copy 10 bytes, which do not exist. Hence you read memory you should not causing Undefined Behaviour (which gives you the SegFault).
You should do something like you did with malloc() for str or declare a local array like char chatTemp[10]. Note: malloc() does not require a cast in C.

If you want to read twice and put the results next to each other in the same buffer, you don't need a temporary buffer for that: you can use pointer arithmetic to tell read to use the second half of the original buffer. Like so:
char buf[10];
ssize_t nread = read(0, buf, 5);
if (nread < 0)
error();
else
{
nread = read(0, buf + nread, sizeof buf - nread);
if (nread < 0)
error();
}

You need to give a file descriptor as a first parameter to read function.. Also you need to allocate char * buffer instead of char tempChar;
Check sample usage

Related

How to use fscanf() for two strings (of ANY length) and dynamically allocate/de-allocate the memory properly

I need to read an input .txt file and print out two separate strings from each line in the file. I used a while loop and a fscanf function to get each string and ignore blank space between. If the strings in a line of the input file are too long, I get a segmentation fault. However, I am also getting a munmap_chunk(): invalid pointer error when I run my executable.
If I don't allocate memory for string1 and string2, fscanf doesn't work properly. I believe fscanf is changing the pointers to string1 and string2, which is causing the munmap_chunk() error. However, I need to de-allocate the memory I gave string1 and string2 so I don't have memory leaks.
How do I scan this file for strings (of ANY length) and de-allocate the memory properly?
int main(int argc, char *argv[])
{
char *string1;
char *string2;
string1 = (char *)malloc(sizeof(string1)); //these strings need memory allocated for the fscanf to function properly
string2 = (char *)malloc(sizeof(string2));
FILE* file = fopen(argv[1], "r");
while (fscanf(file, "%s %s", string1, string2) != EOF)
{
printf("%s %s\n", string1, string2);
}
fclose(file);
//Deallocating memory
free(string1);
free(string2);
return 0;
}
'fscanf' does not change pointers but it can corrupt memory if you do not allocate enough space for your input.
And you are not allocating the memory correctly: string1 and string2 are pointers, so all you are allocating is a size of a pointer (4 or 8 bytes depending on your system).
If you need to read a line from a file and you do not know the maximum length of the line in advance, you can not use fscanf.
You need to allocate a starting buffer, say something like:
string1 = malloc(512 * sizeof(char));
Were 512 is an arbitrary but reasonably large length for a line.
You then use fread to read one byte at a time in a loop, and check for end of line (usually '\n').
You must also count how much you read, and if the line is longer than 512 bytes, use realloc to increase the size of your buffer, like so:
if (bytesRead == (string1Size - 1) && curByte != '\n') {
string1Size += 512;
string1 = realloc(string1, string1Size);
}
Here, bytesRead is an int variable counting how many bytes you successfully read so far, and string1Size is also int variable used to track the size of string1 buffer.
string1 = (char *)malloc(sizeof(string1)); allocates memory for just 4 or 8 characters because string1 is a char * and that's how big a pointer is.
To allocate memory for let's say 100 characters you need to do char *string1 = malloc(sizeof(char) * 100).
How do I scan this file for strings (of ANY length) and de-allocate the memory properly?
You can't with fscanf because it mixes reading input with parsing input. You don't know what's going to be read before you parse it.
Instead, read the line into a large buffer where you can examine it. Once you know how big the pieces are you can allocate just the right amount of memory and copy to it.
Because we are reusing the line buffer, and throwing it away when we're done, we can make it as large as we think we'll ever need. 1024 or 4096 are often good choices. I like BUFSIZ.
char line[BUFSIZ];
while( fgets(line, sizeof(line), file) ) {
// now parse line
}
The parsing can be done in various ways. A simple one is strtok (STRing TOKenize). This tokenizes line in place. Copy them to the right amount of memory with strdup.
char line[BUFSIZ];
while( fgets(line, sizeof(line), file) ) {
char words[2];
int i = 0;
for(
char *word = strtok(line, " ");
word;
word = strtok(NULL, " ")
) {
words[i] = strdup(word);
i++;
}
printf("%s %s", words[0], words[1]);
free(words[0]);
free(words[1]);
}
line and words are allocated on the stack, they will be freed automatically. But the memory allocated by strdup is on the heap, it needs to be freed.

How to fix gibberish printed after use strtok

I have uni project, I need to check if the syntax is right. I get pointer to a string, and check if the first token acceptable. In case it's OK, i move forward. But in case it's not OK, i need to print what is wrong.
What i did is to create a buffer since i can't change the original string.
After that i use strtok to cut the buffer, and look if the token i got is acceptable.
char *str = "sz = 12345";
printf("The check of MACRO: %d\n", isMacro(str));
int isMacro(char *str)
{
char buf = NULL;
char *token;
strcpy(&buf,str);
token = strtok(&buf," ");
printf("You here, value token is %s\n",token);
}
I expected that printf would print the 'sz' but it prints:
You here, value str is sz<▒R
char buf = NULL;
This is a type error. buf is a single character, but NULL is a pointer value. You can't store a pointer in a char.
strcpy(&buf,str);
This code has undefined behavior (unless str happens to be an empty string). buf is not a buffer, it is a single char, so it does not have room to store a whole string.
If you want to make a copy of a string, you need to allocate enough memory for all of its characters:
You could use strdup (which is in POSIX, but not standard C):
char *buf = strdup(str);
if (!buf) {
... handle error ...
}
...
free(buf);
You could replicate strdup manually:
char *buf = malloc(strlen(str) + 1);
if (!buf) {
... handle error ...
}
strcpy(buf, str);
...
free(buf);
You could use a variable-length array (but you're limited by the size of your stack and you have no way to check for errors):
char buf[strlen(str) + 1];
strcpy(buf, str);
...
buf is a single char instead of a pointer to a char. In fact, if you're planning to do strcpy to copy a string to it, you need to allocate memory first using malloc. Instead I'd suggest you to use a function like strdup instead of strcpy to create a copy of the original string to modify it using strtok. Remember to free the strduped string later.
Something like this.
int isMacro(char *str)
{
char *buf = NULL;
char *token;
buf = strdup(str);
token = strtok(buf," ");
printf("You here, value of token is %s\n",token);
free(buf);
}

Memory of first element in dynamic char array

My array is defined like this
int buffSize = 80;
char* buff = (char*) malloc(sizeof(char) * buffSize);
First, I thought &buff should be the same as &buff[0], but apparently, it isn't! Did I miss something here?
This statement prints two different values for those two:
printf("COMPARE: buff=%u, buff[0]=%u\n", &buff, &buff[0]);
Second, the reason I asked is because I'm trying to create a big buffer and "manually" divide it up to use with getline.
Basically, I'd like to do something like this:
int byte_read, total_read = 0;
do
{
read = getline(&buff[totalRead], buffSize, inFile); //where inFile is just a file handler
totalRead += read;
}
while (byte_read > 0);
buff is a pointer, and &buff is the address of that pointer. On the other hand, &buff[0] is the address of the location the pointer points to, and should have the same value as buff.
In summary, expect buff and &buff[0] to have the same value.

Modify buffer passed as a pointer

I'm trying to read into a buffer passed as a pointer to this function. memcpy() works fine and the data is stored correctly in buffer, but when I access buffer outside of the function it is null. There's some pointer issue I'm not getting here.
Here's the code, I took out most of it, I know it copies the data correctly, but it doesn't pass it to the buffer pointer. Ideas?
int read(file file, char *buffer , int maxlen) {
int bytes_read;
// copy data to file buffer
bytes_read = min(maxlen, file->file_size - file->cursor);
buffer = (char*) malloc(bytes_read);
memcpy(buffer , file->buffer + file->cursor, bytes_read);
return bytes_read;
}
The problem is pretty simple: you are modifying the variable "buffer". Since it is passed by value and not by reference, the calling function doesn't see the change. In order to make the change to buffer visible, you need to pass in a pointer to buffer.
Your function would then look like this:
int read(file file, char **buffer , int maxlen) {
int bytes_read;
// copy data to file buffer
bytes_read = min(maxlen, file->file_size - file->cursor);
*buffer = (char*) malloc(bytes_read);
memcpy(*buffer , file->buffer + file->cursor, bytes_read);
return bytes_read;
}
to call the function:
rv = read(file, &buffer, maxlen);
You cannot modify buffer directly because C uses pass by value with parameters. Therefore it is a copy of the pointer you are modifying. To change the pointer you need to change your function prototype to take a char** and allocate to the first level of indirection on that.
As a crude example of this:
void read(char** buffer , int byte_size) {
*buffer = (char*) malloc(byte_size);
}
and use where required with something like
char* buffer;
read(&buffer,10); /* now buffer points to dynamically allocated array of 10 chars */

How to concat two char * in C?

I receive a char * buffer which have the lenght of 10.
But I want to concat the whole content in my struct which have an variable char *.
typedef struct{
char *buffer;
//..
}file_entry;
file_entry real[128];
int fs_write(char *buffer, int size, int file) {
//every time this function is called buffer have 10 of lenght only
// I want to concat the whole text in my char* in my struct
}
Something like this :
real[i].buffer += buffer;
How can I do this in C ?
In general, do the following (adjust and add error checking as you see fit)
// real[i].buffer += buffer;
// Determine new size
int newSize = strlen(real[i].buffer) + strlen(buffer) + 1;
// Allocate new buffer
char * newBuffer = (char *)malloc(newSize);
// do the copy and concat
strcpy(newBuffer,real[i].buffer);
strcat(newBuffer,buffer); // or strncat
// release old buffer
free(real[i].buffer);
// store new pointer
real[i].buffer = newBuffer;
You can use strcat(3) to concatenate strings. Make sure you have allocated enough space at the destination!
Note that just calling strcat() a bunch of times will result in a Schlemiel the Painter's algorithm. Keeping track of the total length in your structure (or elsewhere, if you prefer) will help you out with that.
I am not clear. Do you want:
to concatenate every one of the 10 character buffers you receive into one array, pointed at by one real[0].buffer, or
do you want each 10 character buffer to be pointed at by a different real[i].buffer, or
something else?
You will need to allocate enough space for the copy of the buffer:
#include <stdlib.h>
//...
int size = 10+1; // need to allocate enough space for a terminating '\0'
char* buff = (char *)malloc(size);
if (buff == NULL) {
fprintf(stderr, "Error: Failed to allocate %d bytes in file: %s, line %d\n",
size, __FILE__, __LINE__ );
exit(1);
}
buff[0] = '\0'; // terminate the string so that strcat can work, if needed
//...
real[i].buffer = buff; // now buffer points at some space
//...
strncpy(real[i].buffer, buffer, size-1);

Resources