c string version of atoi - c

is there any functions like atoi read the buffer to return a string?
fgets(input, data_len, stdin);
return atoi(input + 6); // i need the string
thanks
full code
char *getInput2(char *param) {
data_len=atoi(getenv("CONTENT_LENGTH"));
char input[data_len];
fgets(input, data_len, stdin);
char *r_str;
strcpy (r_str, input+6);
return r_str;
}
finally, internal server error........
char *getInput2(char *param) {
char input[100];
data_len=sizeof(input);
fgets(input, data_len, stdin);
return strdup (input+7);
}
only can return first char......enter 12 only return 1, what's the problem?

I'm not entirely certain what you're asking but if it's how to get the string representation of the integer at offset 6, you can do it as a two-step:
char str[enough_to_hold_datalen_and_then_some];
int val = atoi (input+6);
sprintf (str, "%d", val);
Alternatively, if you want to get a chunk of the string regardless of whether it's made up of digits:
strcpy (str, input+6); // get the rest of the string
strncpy (str, input+6, 4); str[4] = '\0'; // get up to four characters.
If your problem is that input is a local variable to the function and, when you return its address, you get bogus data because it's gone out of scope, I'd use:
return strdup (input+6);
That will return a copy of the string on the heap (which is long-lived as opposed to the stack frame, which is not).
Just remember that you need to free that memory when you're finished with it. And be certain that you actually have six characters in that buffer.
If your C implementation doesn't have a strdup, use this one.
Based on your update, it looks like you're after that last option. With your code:
char *r_str;
strcpy (r_str, input+6);
return r_str;
you are not actually allocating any storage to put the string copy (hence the crash). I would replace that whole bit with a simple:
return strdup (input+6);
as I suggested.
Ha, ha, gotta love those Linux man page writers:
If the destination string of a strcpy() is not large enough (that is, if the programmer was stupid/lazy, and failed to check the size before copying) then anything might happen. Overflowing fixed length strings is a favourite cracker technique.

Assuming you want to return the string, then atoi has nothing to do with it. Instead, your problem is that you cannot return memory of a local variable. Returning memory in C is always difficult; typically, you return dynamically allocated memory and expect the caller to free it:
char* get_value()
{
char input[100];
int data_len = sizeof(input);
char *result;
fgets(input, data_len, stdin);
result = malloc(strlen(input)-5); /* reserve enough memory, including the terminating NUL */
strcpy(result, input+6);
return result;
}
(you can shorten this by using strdup)
Alternatively, you can use a global variable, but that won't be reentrant:
char input[100];
char* get_value()
{
int data_len = sizeof(input);
fgets(input, data_len, stdin);
return input+6;
}

Related

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

Reading an unknown length line from stdin in c with fgets

I am trying to read an unknown length line from stdin using the C language.
I have seen this when looking on the net:
char** str;
gets(&str);
But it seems to cause me some problems and I don't really understand how it is possible to do it this way.
Can you explain me why this example works/doesn't work
and what will be the correct way to implement it (with malloc?)
You don't want a pointer to pointer to char, use an array of chars
char str[128];
or a pointer to char
char *str;
if you choose a pointer you need to reserve space using malloc
str = malloc(128);
Then you can use fgets
fgets(str, 128, stdin);
and remove the trailling newline
char *ptr = strchr(str, '\n');
if (ptr != NULL) *ptr = '\0';
To read an arbitrary long line, you can use getline (a function added to the GNU version of libc):
#define _GNU_SOURCE
#include <stdio.h>
char *foo(FILE * f)
{
int n = 0, result;
char *buf;
result = getline(&buf, &n, f);
if (result < 0) return NULL;
return buf;
}
or your own implementation using fgets and realloc:
char *getline(FILE * f)
{
size_t size = 0;
size_t len = 0;
size_t last = 0;
char *buf = NULL;
do {
size += BUFSIZ; /* BUFSIZ is defined as "the optimal read size for this platform" */
buf = realloc(buf, size); /* realloc(NULL,n) is the same as malloc(n) */
/* Actually do the read. Note that fgets puts a terminal '\0' on the
end of the string, so we make sure we overwrite this */
if (buf == NULL) return NULL;
fgets(buf + last, BUFSIZ, f);
len = strlen(buf);
last = len - 1;
} while (!feof(f) && buf[last] != '\n');
return buf;
}
Call it using
char *str = getline(stdin);
if (str == NULL) {
perror("getline");
exit(EXIT_FAILURE);
}
...
free(str);
More info
Firstly, gets() provides no way of preventing a buffer overrun. That makes it so dangerous it has been removed from the latest C standard. It should not be used. However, the usual usage is something like
char buffer[20];
gets(buffer); /* pray that user enters no more than 19 characters in a line */
Your usage is passing gets() a pointer to a pointer to a pointer to char. That is not what gets() expects, so your code would not even compile.
That element of prayer reflected in the comment is why gets() is so dangerous. If the user enters 20 (or more) characters, gets() will happily write data past the end of buffer. There is no way a programmer can prevent that in code (short of accessing hardware to electrocute the user who enters too much data, which is outside the realm of standard C).
To answer your question, however, the only ways involve allocating a buffer of some size, reading data in some controlled way until that size is reached, reallocating if needed to get a greater size, and continuing until a newline (or end-of-file, or some other error condition on input) is encountered.
malloc() may be used for the initial allocation. malloc() or realloc() may be used for the reallocation (if needed). Bear in mind that a buffer allocated this way must be released (using free()) when the data is no longer needed - otherwise the result is a memory leak.
use the getline() function, this will return the length of the line, and a pointer to the contents of the line in an allocated memory area. (be sure to pass the line pointer to free() when done with it )
"Reading an unknown length line from stdin in c with fgets"
Late response - A Windows approach:
The OP does not specify Linux or Windows, but the viable answers posted in response for this question all seem to have the getline() function in common, which is POSIX only. Functions such as getline() and popen() are very useful and powerful but sadly are not included in Windows environments.
Consequently, implementing such a task in a Windows environment requires a different approach. The link here describes a method that can read input from stdin and has been tested up to 1.8 gigabytes on the system it was developed on. (Also described in the link.)_ The simple code snippet below was tested using the following command line to read large quantities on stdin:
cd c:\dev && dir /s // approximately 1.8Mbyte buffer is returned on my system
Simple example:
#include "cmd_rsp.h"
int main(void)
{
char *buf = {0};
buf = calloc(100, 1);//initialize buffer to some small value
if(!buf)return 0;
cmd_rsp("dir /s", &buf, 100);//recursive directory search on Windows system
printf("%s", buf);
free(buf);
return 0;
}
cmd_rsp() is fully described in the links above, but it is essentially a Windows implementation that includes popen() and getline() like capabilities, packaged up into this very simple function.
if u want to input an unknown length of string or input try using following code.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main()
{
char *m;
clrscr();
printf("please input a string\n");
scanf("%ms",&m);
if (m == NULL)
fprintf(stderr, "That string was too long!\n");
else
{
printf("this is the string %s\n",m);
/* ... any other use of m */
free(m);
}
getch();
return 0;
}
Note that %ms, %as are GNU extensions..

printf bug in C

I'm writing a status function but nothing except for the "Tracked:" is printing out. Can anyone see why? I'm assuming that the '.index' file is just a line by line list of file names.
int git_status() {
FILE *check = fopen(".git/.index", "r");
int count = 0;
char *pointer;
printf("Tracked:\n\n");
while(fgets(pointer, sizeof(pointer), check)){
strtok(pointer, "\n");
printf("%s\n", pointer);
count++;
}
printf("\n%d is the number of files", count);
fclose(check);
}
In C you need to allocate the memory you want for strings. In your case you need to declare either a array of characters with fixed length or dynamically reserve enough memory to contain the characters you are about to read.
For instance, the following is not very safe because p does not point to any memory, it is just an uninitialized address:
char* p;
strcpy(p, "This is a string");
If your lucky your compiler should warn you when you try to do things like the above (you might need to enable warnings, -Wall on gcc).
A better approach might be
char chArray[20];
strcpy(chArray, "This is a string");
or
char *p = malloc(20);
strcpy(p, "This is a string");
free(p);
As for char *fgets(char *s, int size, FILE *stream) you probably want to do something like:
#define BUFFER 128
char buf[BUFFER];
while (fgets(buf, BUFFER, fp) != NULL) { /* TODO */ }
To get your program running you will also probably need to look at how strtok works:
The strtok() function breaks a string into a sequence of zero or
more
nonempty tokens. On the first call to strtok() the string to be parsed
should be specified in str. In each subsequent call that should parse
the same string, str must be NULL.

Why would scanf crash while reading a string?

This is just a small program I wrote to find a problem with a larger one. Everything changes when I add the line with scanf. I know it is not safe, I read other threads concerning printf errors that suggest other functions. Anything but cin is fine. Btw, I didn't choose the type definitions of the 'messages', that came from my teachers, so I cannot change them.
#include <stdio.h>
#include <string.h>
char message1 [] = "amfdalkfaklmdklfamd.";
char message2 [] = "fnmakajkkjlkjs.";
char initializer [] = ".";
char* com;
char* word;
int main()
{
com = initializer;
int i = 1;
while (i !=4)
{
printf ("%s \n", com);
scanf("%s",word);
i++;
};
return 0;
}
The problem: after a single iteration the program exits, nothing is printed.
The reason the scanf will crash is buffer is not initialized: word has not been assigned a value, so it is pointing nowhere.
You can fix it by allocating some memory to your buffer, and limiting scanf to a certain number of characters, like this:
char word[20];
...
scanf("%19s", word);
Note that the number between % and s, which signifies the maximum number of characters in a string, is less by 1 than the length of the actual buffer. This is because of null terminator, which is required for C strings.
com is a pointer whose value is the address of the literal string initializer. Literal strings are contained within read-only memory areas, but the scanf function will attempt to write into the address given to it, this is an access-violation and causes the OS to kill your process, hence the crash you're seeing.
Change your scanf code to resemble this, note the addition of width limit in the %s placeholder, as well as the use of the scanf_s version to ensure there is no buffer overflow.
static int const BufferLength = 2048; // 2KiB should be sufficient
char* buffer = calloc( BufferLength , 1 );
if( buffer == null ) exit(1);
int fieldCount = scanf_s("%2047s", buffer, BufferLength );
if( fieldCount == 1 ) {
// do stuff with `buffer`
}
free( buffer );
Note that calloc zeroes memory before returning, which means that buffer can serve as a null-terminated string directly, whereas a string allocated with malloc cannot (unless you zero it yourself).
word has no memory associated with it.
char* word;
scanf("%s",word);
Could use
char word[100];
word[0] = '\0';
scanf("%99s",word);
If available, use getline().
Although not standard C, getline() will dynamicaly allocate memory for arbitrarily long user input.
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, stdin)) != -1) {
printf("%s", line);
}
free(line);
Linux Programmer's Manual GETLINE(3)

Segmentation fault using strcat

Here is my code :
char *name, name_log="log-";
------getting 'name' from user-----
strcat(name_log, name);
char ext[] = ".log";
strcat(name_log, ext);
What i need to end up with is name_log = "log-'name'.log" but Im getting a segmentation fault error :((. What am I doing wrong and how can I fix it ? Thx
For a start, if this is your code:
char *name, name_log="log-";
then name_log is a char, not a char pointer.
Assuming that's a typo, you cannot append to string literals like that. Modifications to string literals are undefined behaviour.
For a variable sized string, as user appears to be, probably the safest option is to allocate another string large enough to hold the result, something like:
char *name, *name_log = "log-", *ext = ".log";
// Do something to allocate and populate name
char *buffer = malloc (strlen (name_log) + strlen (name) + strlen (ext) + 1);
if (buffer == NULL) {
// Out of memory.
} else {
strcpy (buffer, name_log);
strcat (buffer, name);
strcat (buffer, ext);
// Do something with buffer.
free (buffer);
}
The malloc ensures you have enough space to do all the string operations safely, enough characters for the three components plus a null terminator.
string literals get allocated a fixed amount of memory, generally in a read only section, you instead need to use a buffer.
char buffer[64] = "log-";
strncat(buffer,".log",32);
On a side note, strcat is generally unsafe, you need to use something that that checks the size of the buffer it uses or with limits on what it can concatenate, like strncat.
A completely different solution would be this:
const char *prefix = "log-";
const char *suffix = ".log";
// There's a "char *name" somewhere
int size_needed;
char *result;
size_needed = snprintf(NULL, 0, "%s%s%s", prefix, name, suffix);
result = malloc(size_needed + 1);
snprintf(result, size_needed + 1, "%s%s%s", prefix, name, suffix);
// "result" now contains the desired string.
The nice thing about snprintf is that it returns the number of characters it would write if there was enough space. This can be used by measuring upfront how much memory to allocate which makes complicated and error-prone calculations unnecessary.
If you happen to be on a system with asprintf, it's even easier:
char *result = NULL /* in case asprintf fails */;
asprintf(&result, "log-%s.log", name);
// "result" must be released with "free"
you need to allcocate memory. You cannot add to a string in this way as the string added goes to memory which hasnt been allocated.
you can do
char[20] strarray;
strcat(strarray, "log-");
strcat(strarray, "abcd");
the name_log is pointed at a static place: "log-", which means is could not be modified, while as the first parameter in strcat(), it must be modifiable.
try changing name_log's type char* into char[], e.g.
char[20] name_log = "log-";

Resources