printf bug in C - 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.

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 touch a file to a particular location which was #defined [duplicate]

I'm working in C, and I have to concatenate a few things.
Right now I have this:
message = strcat("TEXT ", var);
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
Now if you have experience in C I'm sure you realize that this gives you a segmentation fault when you try to run it. So how do I work around that?
In C, "strings" are just plain char arrays. Therefore, you can't directly concatenate them with other "strings".
You can use the strcat function, which appends the string pointed to by src to the end of the string pointed to by dest:
char *strcat(char *dest, const char *src);
Here is an example from cplusplus.com:
char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");
For the first parameter, you need to provide the destination buffer itself. The destination buffer must be a char array buffer. E.g.: char buffer[1024];
Make sure that the first parameter has enough space to store what you're trying to copy into it. If available to you, it is safer to use functions like: strcpy_s and strcat_s where you explicitly have to specify the size of the destination buffer.
Note: A string literal cannot be used as a buffer, since it is a constant. Thus, you always have to allocate a char array for the buffer.
The return value of strcat can simply be ignored, it merely returns the same pointer as was passed in as the first argument. It is there for convenience, and allows you to chain the calls into one line of code:
strcat(strcat(str, foo), bar);
So your problem could be solved as follows:
char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);
Avoid using strcat in C code. The cleanest and, most importantly, the safest way is to use snprintf:
char buf[256];
snprintf(buf, sizeof(buf), "%s%s%s%s", str1, str2, str3, str4);
Some commenters raised an issue that the number of arguments may not match the format string and the code will still compile, but most compilers already issue a warning if this is the case.
Strings can also be concatenated at compile time.
#define SCHEMA "test"
#define TABLE "data"
const char *table = SCHEMA "." TABLE ; // note no + or . or anything
const char *qry = // include comments in a string
" SELECT * " // get all fields
" FROM " SCHEMA "." TABLE /* the table */
" WHERE x = 1 " /* the filter */
;
Folks, use strncpy(), strncat(), or snprintf().
Exceeding your buffer space will trash whatever else follows in memory!
(And remember to allow space for the trailing null '\0' character!)
Also malloc and realloc are useful if you don't know ahead of time how many strings are being concatenated.
#include <stdio.h>
#include <string.h>
void example(const char *header, const char **words, size_t num_words)
{
size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */
char *message = (char*) malloc(message_len);
strncat(message, header, message_len);
for(int i = 0; i < num_words; ++i)
{
message_len += 1 + strlen(words[i]); /* 1 + for separator ';' */
message = (char*) realloc(message, message_len);
strncat(strncat(message, ";", message_len), words[i], message_len);
}
puts(message);
free(message);
}
Best way to do it without having a limited buffer size is by using asprintf()
char* concat(const char* str1, const char* str2)
{
char* result;
asprintf(&result, "%s%s", str1, str2);
return result;
}
If you have experience in C you will notice that strings are only char arrays where the last character is a null character.
Now that is quite inconvenient as you have to find the last character in order to append something. strcat will do that for you.
So strcat searches through the first argument for a null character. Then it will replace this with the second argument's content (until that ends in a null).
Now let's go through your code:
message = strcat("TEXT " + var);
Here you are adding something to the pointer to the text "TEXT" (the type of "TEXT" is const char*. A pointer.).
That will usually not work. Also modifying the "TEXT" array will not work as it is usually placed in a constant segment.
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
That might work better, except that you are again trying to modify static texts. strcat is not allocating new memory for the result.
I would propose to do something like this instead:
sprintf(message2, "TEXT %s TEXT %s", foo, bar);
Read the documentation of sprintf to check for it's options.
And now an important point:
Ensure that the buffer has enough space to hold the text AND the null character. There are a couple of functions that can help you, e.g., strncat and special versions of printf that allocate the buffer for you.
Not ensuring the buffer size will lead to memory corruption and remotely exploitable bugs.
Do not forget to initialize the output buffer. The first argument to strcat must be a null terminated string with enough extra space allocated for the resulting string:
char out[1024] = ""; // must be initialized
strcat( out, null_terminated_string );
// null_terminated_string has less than 1023 chars
As people pointed out string handling improved much. So you may want to learn how to use the C++ string library instead of C-style strings. However here is a solution in pure C
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void appendToHello(const char *s) {
const char *const hello = "hello ";
const size_t sLength = strlen(s);
const size_t helloLength = strlen(hello);
const size_t totalLength = sLength + helloLength;
char *const strBuf = malloc(totalLength + 1);
if (strBuf == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(strBuf, hello);
strcpy(strBuf + helloLength, s);
puts(strBuf);
free(strBuf);
}
int main (void) {
appendToHello("blah blah");
return 0;
}
I am not sure whether it is correct/safe but right now I could not find a better way to do this in ANSI C.
It is undefined behaviour to attempt to modify string literals, which is what something like:
strcat ("Hello, ", name);
will attempt to do. It will try to tack on the name string to the end of the string literal "Hello, ", which is not well defined.
Try something this. It achieves what you appear to be trying to do:
char message[1000];
strcpy (message, "TEXT ");
strcat (message, var);
This creates a buffer area that is allowed to be modified and then copies both the string literal and other text to it. Just be careful with buffer overflows. If you control the input data (or check it before-hand), it's fine to use fixed length buffers like I have.
Otherwise, you should use mitigation strategies such as allocating enough memory from the heap to ensure you can handle it. In other words, something like:
const static char TEXT[] = "TEXT ";
// Make *sure* you have enough space.
char *message = malloc (sizeof(TEXT) + strlen(var) + 1);
if (message == NULL)
handleOutOfMemoryIntelligently();
strcpy (message, TEXT);
strcat (message, var);
// Need to free message at some point after you're done with it.
The first argument of strcat() needs to be able to hold enough space for the concatenated string. So allocate a buffer with enough space to receive the result.
char bigEnough[64] = "";
strcat(bigEnough, "TEXT");
strcat(bigEnough, foo);
/* and so on */
strcat() will concatenate the second argument with the first argument, and store the result in the first argument, the returned char* is simply this first argument, and only for your convenience.
You do not get a newly allocated string with the first and second argument concatenated, which I'd guess you expected based on your code.
You can write your own function that does the same thing as strcat() but that doesn't change anything:
#define MAX_STRING_LENGTH 1000
char *strcat_const(const char *str1,const char *str2){
static char buffer[MAX_STRING_LENGTH];
strncpy(buffer,str1,MAX_STRING_LENGTH);
if(strlen(str1) < MAX_STRING_LENGTH){
strncat(buffer,str2,MAX_STRING_LENGTH - strlen(buffer));
}
buffer[MAX_STRING_LENGTH - 1] = '\0';
return buffer;
}
int main(int argc,char *argv[]){
printf("%s",strcat_const("Hello ","world")); //Prints "Hello world"
return 0;
}
If both strings together are more than 1000 characters long, it will cut the string at 1000 characters. You can change the value of MAX_STRING_LENGTH to suit your needs.
You are trying to copy a string into an address that is statically allocated. You need to cat into a buffer.
Specifically:
...snip...
destination
Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.
...snip...
http://www.cplusplus.com/reference/clibrary/cstring/strcat.html
There's an example here as well.
Assuming you have a char[fixed_size] rather than a char*, you can use a single, creative macro to do it all at once with a <<cout<<like ordering ("rather %s the disjointed %s\n", "than", "printf style format"). If you are working with embedded systems, this method will also allow you to leave out malloc and the large *printf family of functions like snprintf() (This keeps dietlibc from complaining about *printf too)
#include <unistd.h> //for the write example
//note: you should check if offset==sizeof(buf) after use
#define strcpyALL(buf, offset, ...) do{ \
char *bp=(char*)(buf+offset); /*so we can add to the end of a string*/ \
const char *s, \
*a[] = { __VA_ARGS__,NULL}, \
**ss=a; \
while((s=*ss++)) \
while((*s)&&(++offset<(int)sizeof(buf))) \
*bp++=*s++; \
if (offset!=sizeof(buf))*bp=0; \
}while(0)
char buf[256];
int len=0;
strcpyALL(buf,len,
"The config file is in:\n\t",getenv("HOME"),"/.config/",argv[0],"/config.rc\n"
);
if (len<sizeof(buf))
write(1,buf,len); //outputs our message to stdout
else
write(2,"error\n",6);
//but we can keep adding on because we kept track of the length
//this allows printf-like buffering to minimize number of syscalls to write
//set len back to 0 if you don't want this behavior
strcpyALL(buf,len,"Thanks for using ",argv[0],"!\n");
if (len<sizeof(buf))
write(1,buf,len); //outputs both messages
else
write(2,"error\n",6);
Note 1, you typically wouldn't use argv[0] like this - just an example
Note 2, you can use any function that outputs a char*, including nonstandard functions like itoa() for converting integers to string types.
Note 3, if you are already using printf anywhere in your program there is no reason not to use snprintf(), since the compiled code would be larger (but inlined and significantly faster)
int main()
{
char input[100];
gets(input);
char str[101];
strcpy(str, " ");
strcat(str, input);
char *p = str;
while(*p) {
if(*p == ' ' && isalpha(*(p+1)) != 0)
printf("%c",*(p+1));
p++;
}
return 0;
}
Try something similar to this:
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[])
{
// Insert code here...
char firstname[100], secondname[100];
printf("Enter First Name: ");
fgets(firstname, 100, stdin);
printf("Enter Second Name: ");
fgets(secondname,100,stdin);
firstname[strlen(firstname)-1]= '\0';
printf("fullname is %s %s", firstname, secondname);
return 0;
}
This was my solution
#include <stdlib.h>
#include <stdarg.h>
char *strconcat(int num_args, ...) {
int strsize = 0;
va_list ap;
va_start(ap, num_args);
for (int i = 0; i < num_args; i++)
strsize += strlen(va_arg(ap, char*));
char *res = malloc(strsize+1);
strsize = 0;
va_start(ap, num_args);
for (int i = 0; i < num_args; i++) {
char *s = va_arg(ap, char*);
strcpy(res+strsize, s);
strsize += strlen(s);
}
va_end(ap);
res[strsize] = '\0';
return res;
}
but you need to specify how many strings you're going to concatenate
char *str = strconcat(3, "testing ", "this ", "thing");

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)

Storing a string in char* in C

In the code below, I hope you can see that I have a char* variable and that I want to read in a string from a file. I then want to pass this string back from the function. I'm rather confused by pointers so I'm not too sure what I'm supposed to do really.
The purpose of this is to then pass the array to another function to be searched for a name.
Unfortunately the program crashes as a result and I've no idea why.
char* ObtainName(FILE *fp)
{
char* temp;
int i = 0;
temp = fgetc(fp);
while(temp != '\n')
{
temp = fgetc(fp);
i++;
}
printf("%s", temp);
return temp;
}
Any help would be vastly appreciated.
fgetc returns an int, not a char*. This int is a character from the stream, or EOF if you reach the end of the file.
You're implicitly casting the int to a char*, i.e., interpreting it as an address (turn your warnings on.) When you call printf it reads that address and continues to read a character at a time looking for the null terminator which ends the string, but that address is almost certainly invalid. This is undefined behavior.
I've taken some liberties with what you wanted to accomplish. Rather that deal with pointers, you can just use a fixed sized array as long as you can set a maximum length. I've also included several checks so that you don't run off the end of the buffer or the end of the file. Also important is to make sure that you have a null termination '\0' at the end of the string.
#define MAX_LEN 100
char* ObtainName(FILE *fp)
{
static char temp[MAX_LEN];
int i = 0;
while(i < MAX_LEN-1)
{
if (feof(fp))
{
break;
}
temp[i] = fgetc(fp);
if (temp[i] == '\n')
{
break;
}
i++;
}
temp[i] = '\0';
printf("%s", temp);
return temp;
}
So, there are several problems here:
You're not setting aside any storage for the string contents;
You're not storing the string contents correctly;
You're attempting to read memory that doesn't belong to you;
The way you're attempting to return the string is going to give you heartburn.
1. You're not setting aside storage for the string contents
The line
char *temp;
declares temp as a pointer to char; its value will be the address of a single character value. Since it's declared at local scope without the static keyword, its initial value will be indeterminate, and that value may not correspond to a valid memory address.
It does not set aside any storage for the string contents read from fp; that would have to be done as a separate step, which I'll get to below.
2. You're not storing the string contents correctly
The line
temp = fgetc(fp);
reads the next character from fp and assigns it to temp. First of all, this means you're only storing the last character read from the stream, not the whole string. Secondly, and more importantly, you're assigning the result of fgetc() (which returns a value of type int) to an object of type char * (which is treated as an address). You're basically saying "I want to treat the letter 'a' as an address into memory." This brings us to...
3. You're attempting to read memory that doesn't belong to you
In the line
printf("%s", temp);
you're attempting to print out the string beginning at the address stored in temp. Since the last thing you wrote to temp was most likely a character whose value is < 127, you're telling printf to start at a very low and most likely not accessible address, hence the crash.
4. The way you're attempting to return the string is guaranteed to give you heartburn
Since you've defined the function to return a char *, you're going to need to do one of the following:
Allocate memory dynamically to store the string contents, and then pass the responsibility of freeing that memory on to the function calling this one;
Declare an array with the static keyword so that the array doesn't "go away" after the function exits; however, this approach has serious drawbacks;
Change the function definition;
Allocate memory dynamically
You could use dynamic memory allocation routines to set aside a region of storage for the string contents, like so:
char *temp = malloc( MAX_STRING_LENGTH * sizeof *temp );
or
char *temp = calloc( MAX_STRING_LENGTH, sizeof *temp );
and then return temp as you've written.
Both malloc and calloc set aside the number of bytes you specify; calloc will initialize all those bytes to 0, which takes a little more time, but can save your bacon, especially when dealing with text.
The problem is that somebody has to deallocate this memory when its no longer needed; since you return the pointer, whoever calls this function now has the responsibility to call free() when it's done with that string, something like:
void Caller( FILE *fp )
{
...
char *name = ObtainName( fo );
...
free( name );
...
}
This spreads the responsibility for memory management around the program, increasing the chances that somebody will forget to release that memory, leading to memory leaks. Ideally, you'd like to have the same function that allocates the memory free it.
Use a static array
You could declare temp as an array of char and use the static keyword:
static char temp[MAX_STRING_SIZE];
This will set aside MAX_STRING_SIZE characters in the array when the program starts up, and it will be preserved between calls to ObtainName. No need to call free when you're done.
The problem with this approach is that by creating a static buffer, the code is not re-entrant; if ObtainName called another function which in turn called ObtainName again, that new call will clobber whatever was in the buffer before.
Why not just declare temp as
char temp[MAX_STRING_SIZE];
without the static keyword? The problem is that when ObtainName exits, the temp array ceases to exist (or rather, the memory it was using is available for someone else to use). That pointer you return is no longer valid, and the contents of the array may be overwritten before you can access it again.
Change the function definition
Ideally, you'd like for ObtainName to not have to worry about the memory it has to write to. The best way to achieve that is for the caller to pass target buffer as a parameter, along with the buffer's size:
int ObtainName( FILE *fp, char *buffer, size_t bufferSize )
{
...
}
This way, ObtainName writes data into the location that the caller specifies (useful if you want to obtain multiple names for different purposes). The function will return an integer value, which can be a simple success or failure, or an error code indicating why the function failed, etc.
Note that if you're reading text, you don't have to read character by character; you can use functions like fgets() or fscanf() to read an entire string at a time.
Use fscanf if you want to read whitespace-delimited strings (i.e., if the input file contains "This is a test", fscanf( fp, "%s", temp); will only read "This"). If you want to read an entire line (delimited by a newline character), use fgets().
Assuming you want to read an individual string at a time, you'd use something like the following (assumes C99):
#define FMT_SIZE 20
...
int ObtainName( FILE *fp, char *buffer, size_t bufsize )
{
int result = 1; // assume success
int scanfResult = 0;
char fmt[FMT_SIZE];
sprintf( fmt, "%%%zus", bufsize - 1 );
scanfResult = fscanf( fp, fmt, buffer );
if ( scanfResult == EOF )
{
// hit end-of-file before reading any text
result = 0;
}
else if ( scanfResult == 0 )
{
// did not read anything from input stream
result = 0;
}
else
{
result = 1;
}
return result;
}
So what's this noise
char fmt[FMT_SIZE];
sprintf( fmt, "%%%zus", bufsize - 1 );
about? There is a very nasty security hole in fscanf() when you use the %s or %[ conversion specifiers without a maximum length specifier. The %s conversion specifier tells fscanf to read characters until it sees a whitespace character; if there are more non-whitespace characters in the stream than the buffer is sized to hold, fscanf will store those extra characters past the end of the buffer, clobbering whatever memory is following it. This is a common malware exploit. So we want to specify a maximum length for the input; for example, %20s says to read no more than 20 characters from the stream and store them to the buffer.
Unfortunately, since the buffer length is passed in as an argument, we can't write something like %20s, and fscanf doesn't give us a way to specify the length as an argument the way fprintf does. So we have to create a separate format string, which we store in fmt. If the input buffer length is 10, then the format string will be %10s. If the input buffer length is 1000, then the format string will be %1000s.
The following code expands on that in your question, and returns the string in allocated storage:
char* ObtainName(FILE *fp)
{
int temp;
int i = 1;
char *string = malloc(i);
if(NULL == string)
{
fprintf(stderr, "malloc() failed\n");
goto CLEANUP;
}
*string = '\0';
temp = fgetc(fp);
while(temp != '\n')
{
char *newMem;
++i;
newMem=realloc(string, i);
if(NULL==newMem)
{
fprintf(stderr, "realloc() failed.\n");
goto CLEANUP;
}
string=newMem;
string[i-1] = temp;
string[i] = '\0';
temp = fgetc(fp);
}
CLEANUP:
printf("%s", string);
return(string);
}
Take care to 'free()' the string returned by this function, or a memory leak will occur.

c string version of atoi

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

Resources