Trouble while reading from socket - c

I am trying to read characters from a socket; here is the function I created for this, largely inspired from Here, where I remove some unrelevant parts here (this sample is compiling correctly).
int process(int socketfd, void *buffer, int n)
{
int totread = 0;
char ch;
int numread;
for(;;)
{
numread = read(socketfd, &ch, 1);
if(numread == 0) {
if (totread == 0) {
return 0;
} else {
break;
}
} else {
if(totread < n-1) {
totread++;
printf("totread: %d\n", totread);
printf("Here is OK, ch value gets printed %c\n", ch);
*buffer++ = ch;
printf("With help provided, this line gets printed\n");
printf("But the value <%s> of buffer, is blank (<> output)\n, buffer);
}
if (ch == '\n') {
printf("%c\n", ch);
printf("%s\n", buffer);
break;
}
}
}
return totread;
}
I can't understand why the second line does not get printed.
Obviously, the *buf++ = ch instruction is faulty; But it looks like correct. It simply affects the character read to the next value of the array of characters buf. I don't see errors or warnings at compile time, the client disconnects after the first line gets printed, and the second one is not reached.
EDIT
Here is how I initialize my buffer:
char *buffer = "";
int l = process(newsockfd, buffer, 100);
printf("Number read (function network) %d\n", l);
This is probably not the appropriate way to do it; I have also tried specifying a fixed length such as char buffer = [255]; The function does not exit then but nothing get printed. I'm quite a newbie in C programming, many thanks for your help!

int process(..., void * b, ...
{
...
*b++ = ...
Dereferencing and/or incrementing a void-pointer is not valid C. The compiler should have at least warned you about this.
Recompile your code with all warnings on (for gcc pass the options -Wall -Wextra -pedantic for this). Then fix the code until no more warning are issued.
Referring your edit on how the function in question is called:
This
char *buffer = "";
does not declare a buffer, but just a pointer. This pointer points to a string literal of size 1. String literals a constant by definition.
To summarise: You provide to your process()-function a pointer to constant memory of size 1.
Issues with this:
You cannnot read into constant memory.
An even if 1. would not apply you could only read in 1 byte.
To fix this change the code as follows:
char buffer[100] = ""; /* Define a buffer of 100 characters size and
initialise it to all `0`s. */
int l = process(newsockfd, buffer, 100);
As per process() blocking, you need to look at the read() function: If it gets called but the sender does not send anything it simply does not return as long as the connection is still up.
And: Make process() handle the value passed in as n.

Try changing the first line to
char *buf = (char *) buffer;
and compile using gcc with -Werror on

Related

Function that reads a string from a file of unknown length

I've been trying to piece together a function that allows me to create a string out of a given file of unknown length.
What it's supposed to do, is set the size of the output string to a single character, then for each character besides EOF, increment the size of the string by 1 and add the newly read character to it.
void readstring(FILE *f, char *s[])
{
int size = 1;
int c = 0, i = 0;
s = malloc(size*sizeof(char));
while(c != -1)
{
c = fgetc(f);
s[i] = (char)c;
i++;
if(i == size)
{
size++;
s = realloc(s, size*sizeof(char));
}
}
s[i] = '\0';
}
int main()
{
char *in = malloc(2*sizeof(char));
FILE *IN;
IN = fopen("in.txt", "r");
readstring(IN, in);
printf("%s",&in);
fclose(IN);
free(in);
return 0;
}
If you are on a POSIX compliant system (any modern Linux), don't try to reinvent the wheel. Just use getline(). It will do the tricky stuff of managing a growing buffer for you, and return a suitably malloc()'ed string.
You are assigning the result of malloc()/realloc() to s instead of *s. s is purely local to readstring(), *s is the pointer variable that s points to. Pass in the adress of the pointer in main. Correct code looks like this:
void foo(char** out_string) {
*out_string = malloc(...);
}
int main() {
char* string;
foo(&string);
}
Without the address taking & and pointer dereferenciation *, your main() cannot know where readstring() has stored the characters.
You also need to dereference the double pointer when you set the characters of the string: Use (*s)[i] instead of s[i], as s[i] denotes a pointer, not a character.
Also, try running your program with valgrind, and see if you can learn from the errors that it will spew out at you. It's a great tool for debugging memory related problems.

Put characters from a char array in a string till a specific character is found

I'd like a reliable method to read the characters from a character array and put them in a string. This will happen till a \r is found. I can iterate through the array but have no good way to put that in a string. I am afraid to use malloc since, at times, puts garbage value in a string.
Here payload is the HTTP data from a TCP packet. \r\n\r\n indicates the end of the payload.
My code so far to iterate through the character array:
void print_payload(const unsigned char *payload, int len) {
int i;
const unsigned char *ch = payload;
for (i = 0; i < len; i++) {
if (strncmp((char*) ch, "\r\n\r\n", 4) == 0) {
// Indicates end of payload data.
break;
} else if (strncmp((char*) ch, "\r\n", 2) == 0) {
//Indicates EOL
printf("\r\n");
ch++;
i++;
} else if(strncmp((char*) ch, "Host:", 5) == 0){
printf("Host: ");
const unsigned char *del = ch + 6;
int i = 0;
while (del[i] != 13 ){
/*
*13 is decimal value for '\r'.
* The characters below are to be inserted
* in a string. Not sure how though.
*/
printf("%c",del[i]);
i++;
}
} else if(strncmp((char*) ch, "User-Agent: ", 11) == 0){
/*
* It has to implemented here as well.
* And in every case where my string matches.
*/
printf("UserAgent: ");
const unsigned char* del = ch + 11;
int i = 0;
while(del[i] != 13){
printf("%c")
}
}
ch++;
}
printf("\r\n\r\n");
printf("\n");
return;
}
Can somebody help me achieve this? I know this is basic but I'm still learning C Programming and am not sure how to do this. Thank in advance.
You have a few options. First, if you can limit the size of the string, and do not need it outside of the function, then a char array would work:
#define STRING_MAX_LEN 999//chux mentions this is better then just putting "1000" in the array[] - 1000 needs to make sense in terms of the program, or something you wish to enforce (and checked!)
char newString[STRING_MAX_LEN+1] = {0};//Initialize to NULL value.
There is no reason to fear malloc though - just remember to work safely and free, and you should be fine:
char *newString = malloc(sizeof(char)*(len+1)); //Better limit on needed space - +1 for a final '\0'.
if (!newString) //Oh no! hard fail.
//do Something
}
memset(newString,0,sizeof(char)*(len+1)); //No garbage in my new string anymore!
...
...
free(newString);
//Finish up with program
You will not even have to append a '\0' - you are already sure the buffer is full of them, so you a valid C string. Note sizeof(char) may be redundant but I like to keep it anyway, in case one day it will not equal 1.
Note if you have to return the new string for some reason you must use a dynamically allocated array, using malloc. Finally, if you only need to check/hold one sub-string at a time, then re-using the same string is preferable.
void print_payload(const unsigned char *payload, int len)
{
int i;
char c;
char *p;
p = (char*)payload;
for(i=0;i<len;i++) {
if(!strncmp(&p[i],"\r\n\r\n",4)) {
c = p[i+4];
p[i+4] = 0;
break;
}
}
if(i==len) {
return;
}
printf("%s\n",p);
p[i+4] = c;
}

malloc'd pointer resetting itself to NULL?

I am getting some pretty strange behavior using malloc. I am never allocating more than 4kB, so this seems especially strange to me. My main looks something like:
int main(int argc, char **argv)
{
char *buf;
char *raw = malloc(1024);
fgets(raw, 1024, stdin);
parse(raw, &buf); // Process raw input, get parse length
printf("raw: 0x%p\n", raw); // Outputs 0x00000000
if(raw != NULL)
{ // Only prints when less than 10 characters are entered
free(raw);
printf("raw is not NULL\n");
}
free(buf);
return 0;
}
When I enter less than 10 characters this works okay, when I enter exactly 10 characters I get a segmentation fault, and when I enter more than 10 the output shows that raw is NULL. It should be noted that the size of raw is 1024 malloc'd bytes, so I should have more room to work with.
The parse function is:
int parse(char *src, char **dst)
{
int num_valid = 0, len = strlen(src), j = 0;
// Count number of valid characters
for(int i = 0; i < len; i++)
{
if(src[i] == 'A')
++num_valid;
}
*dst = malloc(num_valid);
for(int i = 0; i < len; i++)
{
if(src[i] == 'A')
*dst[j++] = src[i];
}
// For debugging:
printf("src: 0x%p\n", src); // outputs correct address
return num_valid;
}
This function outputs the correct address, and properly allocates and fills dst. I modified the code here slightly, this is basically a very reduced form of my code. I compiled and ran it (gcc test.c -Werror -Wall) with the same results. It is only after this function returns that my raw pointer becomes NULL, or I get a segfault.
Can someone point me in the right direction? Tell me what exactly I am doing wrong? I've been debugging this little piece of code since yesterday and it is driving me mad.
This doesn't mean what you think it means:
*dst[j++] = src[i];
You meant
(*dst)[j++] = src[i];
What you wrote means:
*(dst[j++]) = src[i];
dst[1] is whatever happens to follow the variable buf, so you're using an address from a random memory location and overwriting whatever it might point to; that's undefined behaviour.
As #pm100 points out in a comment, keeping the buffer in a temporary variable is generally better style:
char* buf = malloc(num_valid);
if (!buf) { /* Handle allocation failure */ }
*dst = buf;
/* ... */
/* In loop */
buf[j++] = src[i];

Returning a string [char pointer] from a function [duplicate]

This question already has answers here:
Return char[]/string from a function [duplicate]
(5 answers)
Closed 8 years ago.
I am writing a program that returns a string from stdin, but i am getting warning that it returns an adress of local wariable. How can i return the string?
thanks in advance
#include <stdio.h>
char* readLine()
{
int i;
char input[1024];
for(i=0;i<1024;i++)
{
input[i]=fgetc(stdin);
if(input[i]=='\n')
{
break;
}
}
return input;
}
int main()
{
printf("%s",readLine());
return 0;
}
This should work for you:
You can pass input from main as reference:
#include <stdio.h>
char * readLine(char * input, int length) {
int i;
for(i = 0; i < length; i++) {
input[i] = fgetc(stdin);
input[length] = '\0';
if(input[i] == '\n')
break;
}
return input;
}
int main() {
int length = 1024;
char input[length+1];
printf("%s", readLine(input, length));
return 0;
}
Try to do something like that instead:
#include <stdio.h>
char* readLine()
{
int i;
char *input;
if ((input = malloc(sizeof(char) * 1024)) == NULL)
return (NULL);
for(i=0;i<1024;i++)
{
input[i]=fgetc(stdin);
if(input[i]=='\n')
{
input[i] = '\0';
break;
}
}
return input;
}
int main()
{
char *str;
if (str = readLine()) != NULL) {
printf("%s\n", str);
free(str);
}
return 0;
}
}
There is nothing wrong here - that is just a WARNING because usually it is a common mistake of new programmers. I used to run into problems with this usage all the time.
The first thing... this "string" is not null-terminated. You'll want to put at the end of that function something like *(input + i) = '\0'; and make either the array size 1025 or the condition i < 1023 (so that the null character isn't assigned beyond the end of the buffer), because at the moment using this array in a function that expects null termination will cause it to possibly continue past the end of the array, resulting in a memory access violation. Alternately, you could use memset(input,0,1024);, just still make sure that the condition is something like i < 1023 so that the standard input you receive doesn't end up writing all the way to the last null character in the array.
The other problem is that this memory is local, as in it "belongs" to this function. And for the usage you have here, it is probably just fine to use the same memory... if you plan to call the function, do something with the result, and then call the function again, do something with the result... But if you want to keep what's given to you by it, you'll have to either (1) copy the string to another buffer that isn't going to be written to again when the function is called in the future, or (2) make the function allocate a new buffer each time it runs, and then be sure to delete that memory when you're done with it. For example, instead of char input [1024]; (which by the way would have the same pointer for the life of the program, so it's not really necessary to return it each time) you could write char* input = malloc(1024); and later, when the caller is done with the string, you should free(input);. (Of course, the name might not be input in this case since you would probably not want to free the memory in the function whose purpose is to allocate it.)
I will edit this later with code showing changes.

Why am I getting a segmentation fault?

I'm trying to write a program that takes in a plaintext file as it's argument and parses through it, adding all the numbers together and then print out the sum. The following is my code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
static int sumNumbers(char filename[])
{
int sum = 0;
FILE *file = fopen(filename, "r");
char *str;
while (fgets(str, sizeof BUFSIZ, file))
{
while (*str != '\0')
{
if (isdigit(*str))
{
sum += atoi(str);
str++;
while (isdigit(*str))
str++;
continue;
}
str++;
}
}
fclose(file);
return sum;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Please enter the filename as the argument.\n");
exit(EXIT_FAILURE);
}
else
{
printf("The sum of all the numbers in the file is : %d\n", sumNumbers(argv[1]));
exit(EXIT_SUCCESS);
}
return 0;
}
And the text file I'm using is:
This a rather boring text file with
some random numbers scattered
throughout it.
Here is one: 87 and here is another: 3
and finally two last numbers: 12
19381. Done. Phew.
When I compile and try to run it, I get a segmentation fault.
You've not allocated space for the buffer.The pointer str is just a dangling pointer. So your program effectively dumps the data read from the file into memory location which you don't own, leading to the segmentation fault.
You need:
char *str;
str = malloc(BUFSIZ); // this is missing..also free() the mem once done using it.
or just:
char str[BUFSIZ]; // but then you can't do str++, you'll have to use another
// pointer say char *ptr = str; and use it in place of str.
EDIT:
There is another bug in:
while (fgets(str, sizeof BUFSIZ, file))
The 2nd argument should be BUFSIZ not sizeof BUFSIZ.
Why?
Because the 2nd argument is the maximum number of characters to be read into the buffer including the null-character. Since sizeof BUFSIZ is 4 you can read max upto 3 char into the buffer. That is reason why 19381 was being read as 193 and then 81<space>.
You haven't allocated any memory to populate str. fgets takes as its first argument a buffer, not an unassigned pointer.
Instead of char *str; you need to define a reasonably sized buffer, say, char str[BUFSIZ];
Because you've not allocated space for your buffer.
A number of people have already addressed the problem you asked about, but I've got a question in return. What exactly do you think this accomplishes:
if (isdigit(*str))
{
if (isdigit(*str))
{
sum += atoi(str);
str++;
while (isdigit(*str))
str++;
continue;
}
}
What's supposed to be the point of two successive if statements with the exact same condition? (Note for the record: neither one has an else clause).
You have declared char* str, but you have not set aside memory for it just yet. You will need to malloc memory for it.
Many memory related errors such as this one can be easily found with valgrind. I'd highly recommend using it as a debugging tool.
char *str;
str has no memory allocated for it. Either use malloc() to allocate some memory for it, or declared it with a predefined size.
char str[MAX_SIZE];
Your program has several bugs:
It does not handle long lines correctly. When you read a buffer of some size it may happen that some number starts at the end of the buffer and continues at the beginning of the next buffer. For example, if you have a buffer of size 4, there might be the input The |numb|er 1|2345| is |larg|e., where the vertical lines indicate the buffer's contents. You would then count the 1 and the 2345 separately.
It calls isdigit with a char as argument. As soon as you read any "large" character (greater than SCHAR_MAX) the behavior is undefined. Your program might crash or produce incorrect results or do whatever it wants to do. To fix this, you must first cast the value to an unsigned char, for example isdigit((unsigned char) *str). Or, as in my code, you can feed it the value from the fgetc function, which is guaranteed to be a valid argument for isdigit.
You use a function that requires a buffer (fgets) but you fail to allocate the buffer. As others noted, the easiest way to get a buffer is to declare a local variable char buffer[BUFSIZ].
You use the str variable for two purposes: To hold the address of the buffer (which should remain constant over the whole execution time) and the pointer for analyzing the text (which changes during the execution). Make these two variables. I would call them buffer and p (short for pointer).
Here is my code:
#include <ctype.h>
#include <stdio.h>
static int sumNumbers(const char *filename)
{
int sum, num, c;
FILE *f;
if ((f = fopen(filename, "r")) == NULL) {
/* TODO: insert error handling here. */
}
sum = 0;
num = 0;
while ((c = fgetc(f)) != EOF) {
if (isdigit(c)) {
num = 10 * num + (c - '0');
} else if (num != 0) {
sum += num;
num = 0;
}
}
if (fclose(f) != 0) {
/* TODO: insert error handling here. */
}
return sum;
}
int main(int argc, char **argv) {
int i;
for (i = 1; i < argc; i++)
printf("%d\t%s\n", sumNumbers(argv[i]), argv[i]);
return 0;
}
Here is a function, that does your job:
static int sumNumbers(char* filename) {
int sum = 0;
FILE *file = fopen(filename, "r");
char buf[BUFSIZ], *str;
while (fgets(buf, BUFSIZ, file))
{
str=buf;
while (*str)
{
if (isdigit(*str))
{
sum += strtol(str, &str, 10);
}
str++;
}
}
fclose(file);
return sum;
}
This doesn't includes error handling, but works quite well. For your file, output will be
The sum of all the numbers in the file is : 19483

Resources