Can anyone explain to me why this isn't working?
#include <stdio.h>
#include <stdlib.h>
char *getline(int lim)
{
char c;
int i;
char *line;
line = malloc(sizeof(char) * lim);
i = 0;
while((c = getchar()) != '\n' && c != EOF && i < lim-1)
{
*line = c;
line++;
i++;
}
*line = '\0';
printf("%s", line);
return line;
}
I'm not worried about the return value right now - just the reason as to why printf("%s", line) isn't working.
Thanks!
EDIT: fixed to line = malloc(sizeof(char) * lim); but it is still not working.
Solution: the address of *line was being incremented throughout the function. When it was passed to printf(), *line pointed to '\0' because that's where its adress was incremented to. Using a temprorary pointer that stored the original address allocated by malloc() to *line and then passing that pointer into printf(), allowed for the function to walk up the pointer.
Because you are only allocating enough space for a single character in this line:
line = malloc(sizeof(char));
And that is getting filled with the \0 before your printf statement.
I'm guessing you want to change this line to:
/* Allocate enough room for 'lim' - 1 characters and a trailing \0 */
line = malloc(sizeof(char) * lim);
Or even better:
char *line, *tmp;
tmp = line = malloc(sizeof(char) * lim);
And then use tmp in all of your pointer math, this way line will still point to the start of your string.
And I know it's early in your development, but you'll want to make sure you free() the memory that you malloc().
Here is a working version of your function including my suggested changes:
#include <stdio.h>
#include <stdlib.h>
char *getline(int lim)
{
char c;
int i;
char *line, *tmp;
tmp = line = malloc(sizeof(char) * lim);
i = 0;
/* NOTE: 'i' is completely redundant as you can use 'tmp',
* 'line,' and 'lim' to determine if you are going to
* overflow your buffer */
while((c = getchar()) != '\n' && c != EOF && i < lim-1)
{
*tmp = c;
tmp++;
i++;
}
*tmp = '\0';
printf("%s", line);
return line;
}
It looks like you're printing a zero-length string.
*line = '\0';
printf("%s", line);
I presume that you want to store what line was originally (as returned from malloc) and print that.
Everyone has covered these points already, but here is the whole thing all put together:
Edit: Improved the code a little
#include <stdio.h>
#include <stdlib.h>
char *getline(int lim)
{
char *result = malloc(sizeof(char) * lim); // allocate result buffer
int i = 0;
char c;
char *line = result;
while((c = getchar()) != '\n' && c != EOF && i < lim-1)
{
*line = c;
line++;
i++;
}
*line = '\0';
printf("%s", result); // print the result
return result; // return the result buffer (remember to free() it later)
}
You seem to have allocated enough room for only one character. Did you mean the following instead:
line = malloc(lim * sizeof(char));
Also, you don't want to change line after reading each character. Use the following block for your while-loop instead:
*(line + i) = c;
i++;
And finally, to null-terminate the string, use:
*(line + i) = '\0';
Updated-it was a simple typo mistake,but you didn't have to vote me down on it
instead of
char *line= malloc(sizeof(char));
try
int space= //number of how many characters you need on the line
char *line= malloc(sizeof(char)*space);
sorry I meant
char *line= malloc( sizeof(char)*lim)
You're also overwriting memory you don't own. You're malloc'ing one character, setting *line to c, and then incrementing line and repeating.
You need to understand the concept of pointer, and how it's different from a buffer.
In your code, you treat "line" as pointer and buffer at the same time.
You are Making mistake on two points (but you can say same mistake or two ,its upto you). first your pointer should be incremented like
*(line+i) = c;
Due to this reason when you set the Null char at the end of loop you are actually saying the compiler to point the pointer to only this poistion.Hence the pointer is only pointing at Null String not the whole string. As it was constantly being moved in each step of the loop.
So when you tried to print that the pointer has nothing to print. So if you change your statement inside the loop for pointer and assign the value to an express address rather then actually moving the pointer then you problem will be solved.
Note. If you change that line then you also need to modify your Null terminator assignment like this;
*(line+limit) = '\0';
Related
I am a C beginner who has been assigned to write a program that uses pointers to reverse a message. I am having trouble getting the for loop that reads the characters to break after it reads a newline and I don't want to use a while loop.
Below is my code:
#include <stdio.h>
#include <string.h>
int main(){
//declare string
char reverse[100];
//declare pointer
char *first;
//set pointer to point to first element of array
first = &reverse[0];
//get chars until end of input
printf("Enter a message:");
for (first = reverse; *first != '\n'; first++){
scanf("%c", first);
printf("%c", *first);
}
//reverse chars one by one
printf("Reversal: ");
for (first; first >= reverse; first--){
printf("%c", *first);
}
printf("\n");
return 0;
}
Thank you! Any help is appreciated :)
You have effectively implemented gets, a function so dangerous it was removed from the language, with a side of undefined behaviour because *first != '\n' is executed at the start of each iteration of the loop, and *first is an indeterminate value at this point.
first-- and first >= reverse are also a problem as holding a pointer value to one before the start of an object is also undefined behaviour. It is valid C to hold (but not use with unary *) an address one past the end of an array object (C11 ยง6.5.6).
Note, using getchar would be preferable to scanf.
If you do not want the newline in the buffer:
#include <stdio.h>
#define SIZE 100
int main(void) {
char buffer[SIZE];
char *dest = buffer;
for (; dest - buffer < sizeof buffer - 1; dest++)
if (1 != scanf("%c", dest) || '\n' == *dest)
break;
*dest = 0;
while (dest > buffer)
putchar(*--dest);
putchar('\n');
}
If you want the newline in the buffer:
#include <stdio.h>
#define SIZE 100
int main(void) {
char buffer[SIZE];
char *dest = buffer;
for (; dest - buffer < sizeof buffer - 1;)
if (1 != scanf("%c", dest) || '\n' == *dest++)
break;
*dest = 0;
while (dest > buffer)
putchar(*--dest);
putchar('\n');
}
Note the difference in when dest is incremented.
while (dest > buffer)
putchar(*--dest);
works by starting at the null-terminating character, and printing each element that comes before the current one, until our current element is the start of the array.
This can also get extremely terse, and you may be tempted to write something like
/* newline in buffer */
for (; dest - buffer < sizeof buffer - 1 && 1 == scanf("%c", dest) && '\n' != *dest; dest++);
but use of the break keyword can help to keep it readable.
I'm trying to make a simple program where you put some text in it and it write back what you just wrote.
For example if I write "Hello World", the program should write me back "Hello World"
How I think it should work is like that :
loop to check if the current character is '\0'
if not print the current character and reallocate 1 more byte of memory
else stop the loop
So it's looks like an easy thing to do but my attempt is not working correctly, for example if you put only a few characters it is going to write you back with no problem but with longer string.. it is not working at all.
I know it is possible using fgets(), but I would like to understand why my version with scanf() isn't working.
(my code)
#include <stdio.h>
#include <stdlib.h>
int main(void){
int mem = 2;
char * str = malloc(mem);
scanf("%s", str);
while (*str != '\0') {
printf("%c", *str);
realloc(str, mem++);
str++;
}
free(str);
return 0;
}
edit : I was thinking that I only did a small mistake but, after reading the comments it looks like there is a lot of things that I did wrong in this tiny program. I'm going make sure that I better understand how C work and retry to do this program later. Thanks for the help!
Your program could be much more simple
#include <stdio.h>
int main() {
char c;
while( scanf("%c", &c) == 1 ) {
printf("%c", c);
}
return 0;
}
If you're going to use scanf for this, you shouldn't use "%s". (You should never use "%s" without a field width, since this will potentially overflow a buffer. Using "%s" is no better that gets().) If you are going to use a variant of "%s", you need to understand that it will ignore whitespace. The following does almost what you want, except for the whitespace issue. If you want to handle whitespace with precision, you cannot use "%s".
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
void * xrealloc(void *buf, size_t num, size_t siz, void *endvp);
int
main(void)
{
size_t cap = 2;
char *end = NULL;
char *str = xrealloc(NULL, cap, sizeof *str, &end);
/*
* Read 1 char at a time, discarding whitespace. This should
* be done with getchar(). If using scanf, a single char
* should be read with "%c". We use "%1s" here only
* because the question is specifically about `%s`.
* Note that %1s will allow scanf to write up to 2 characters into
* *end, so we need to ensure there is space for the terminator.
*/
while( 1 == scanf("%1s", end++) ){
while( end > str + cap - 2 ){
str = xrealloc(str, cap *= 2, sizeof *str, &end);
}
}
fputs(str, stdout);
free(str);
return 0;
}
void *
xrealloc(void *buf, size_t num, size_t siz, void *endvp)
{
char **endp = endvp;
char *b = buf;
ptrdiff_t offset = b && endp && *endp ? *endp - b : 0;
b = realloc(b, num * siz);
if( b == NULL ){
perror("realloc");
exit(EXIT_FAILURE);
}
if( endp != NULL ){
*endp = b + offset;
}
return b;
}
Reading functions' manuals and searching for similar questions is a great method to get things clearer, and undestand the problem you are facing better :)
Try looking at this question: Reading input of unknown length, and particularly at this answer that uses scanf: scanf answer (I did not verify if that works, but it teaches you another method you can use).
I need to get strings dynamically but as I need to get more than one string, I need to use functions. So far I wrote this
(I put //**** at places i think might be wrong)
char* getstring(char *str);
int main() {
char *str;
strcpy(str,getstring(str));//*****
printf("\nString: %s", str);
return 0;
}
char* getstring(char str[]){//*****
//this part is copy paste from my teacher lol
char c;
int i = 0, j = 1;
str = (char*) malloc (sizeof(char));
printf("Input String:\n ");
while (c != '\n') {//as long as c is not "enter" copy to str
c = getc(stdin);
str = (char*)realloc(str, j * sizeof(char));
str[i] = c;
i++;
j++;
}
str[i] = '\0';//null at the end
printf("\nString: %s", str);
return str;//******
}
printf in the function is working but not back in main function.
I tried returning void, getting rid of *s or adding, making another str2 and tring to strcpy there or not using strcpy at all. Nothing seems to working. Am I misssing something? Or maybe this is not possible at all
//Thank you so much for your answers
Getting the string part can be taken from this answer. Only put a \n as input to the getline funtion.
char * p = getline('\n');
Three things :-
don't cast malloc, check if malloc/realloc is successful and sizeof is not a function.
The problem is not with the function that you are using, but with the way you try copying its result into an uninitialized pointer.
Good news is that you don't have to copy - your function already allocates a string in dynamic memory, so you can copy the pointer directly:
char *str = getstring(str);
This should fix the crash. A few points to consider to make your function better:
main needs to free(str) when it is done in order to avoid memory leak
Store realloc result in a temporary pointer, and do a NULL check to handle out-of-memory situations properly
There are two things to take away from the lesson as it stands now:
(1) You should have one way of returning the reference to the new string, either as an argument passed by reference to the function OR as a return value; you should not be implementing both.
(2) Because the subroutine your teacher gave you allocates memory on the heap, it will be available to any part of your program and you do not have to allocate any memory yourself. You should study the difference between heap memory, global memory, and automatic (stack) memory so you understand the differences between them and know how to work with each type.
(3) Because the memory is already allocated on the heap there is no need to copy the string.
Given these facts, your code can be simplified to something like the following:
int main() {
char *str = getstring();
printf( "\nString: %s", str );
return 0;
}
char* getstring(){
.... etc
Going forward, you want to think about how you de-allocate memory in your programs. For example, in this code the string is never de-allocated. It is a good habit to think about your strategy for de-allocating any memory that you allocate.
Let's simplify the code a bit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getstring()
{
char c = 0;
int i = 0, j = 2;
char *str = NULL;
if ((str = (char*) malloc(sizeof(char))) == NULL)
return NULL;
printf("Input String: ");
while (c = getc(stdin)) {
if (c == '\n') break;
str = (char*) realloc(str, j * sizeof(char));
str[i++] = c;
j++;
}
str[i] = '\0';
printf("getstring() String: %s\n", str);
return str;
}
int main()
{
char *str = getstring();
printf("main() String: %s\n", str);
free(str);
return 0;
}
Then execute:
$ make teststring && ./teststring
cc teststring.c -o teststring
Input String: asdfasfasdf
getstring() String: asdfasfasdf
main() String: asdfasfasdf
i am trying to code a C function which returns a line read from the input as a char* . I am on Windows and i test my program in the command line by giving files as input and output of my program like this:
cl program.c
program < test_in.txt > test_out.txt
This is my (not working) function:
char* getLine(void)
{
char* result = "";
int i, c;
i = 1;
while((c = getchar()) != EOF)
{
*result++ = c;
i++;
if(c == '\n')
return result - i;
}
return result - i;
}
I was expecting it to work because i previously wrote:
char* getString(char* string)
{
//char* result = string; // the following code achieve this.
char* result = "";
int i;
for(i = 1; *result++ = *string++; i++);
return result - i;
}
And these lines of code have a correct behaviour.
Even if every answers will be appreciated, i would be really thankfull
if any of you could explain me why my getString() function works while my getLine() function doesn't.
Your function does not allocate enough space for the string being read. The variable char* result = "" defines a char pointer to a string literal ("", empty string), and you store some arbitrary number of characters into the location pointed to by result.
char* getLine(void)
{
char* result = ""; //you need space to store input
int i, c;
i = 1;
while((c = getchar()) != EOF)
{
*result++ = c; //you should check space
i++;
if(c == '\n')
return result - i; //you should null-terminate
}
return result - i; //you should null-terminate
}
You need to allocate space for your string, which is challenging because you don't know how much space you are going to need a priori. So you need to decide whether to limit how much you read (ala fgets), or dynamically reallocate space as you read more. Also, how to you indicate that you have finished input (reached EOF)?
The following alternative assumes dynamic reallocation is your chosen strategy.
char* getLine(void)
{
int ch; int size=100; size_t pos=0;
char* result = malloc(size*sizeof(char*));
while( (ch=getchar()) != EOF )
{
*result++ = ch;
if( ++pos >= size ) {
realloc(result,size+=100);
//or,realloc(result,size*=2);
if(!result) exit(1); //realloc failed
}
if( c=='\n' ) break;
}
*result = '\0'; //null-terminate
return result - pos;
}
When you are done with the string returned from the above function, please remember to free() the allocated space.
This alternative assumes you provide a buffer to store the string (and specifies the size of the buffer).
char* getLine(char* buffer, size_t size)
{
int ch;
char* result = buffer;
size_t pos=0;
while( (ch=getchar()) != EOF )
{
*result++ = ch;
if( ++pos >= size ) break; //full
if( c=='\n' ) break;
}
*result = '\0'; //null-terminate
return buffer;
}
Both avoid the subtle interaction between detecting EOF, and having enough space to store a character read. The solution is to buffer a character if you read and there is not enough room, and then inject that on a subsequent read. You will also need to null-ter
Both functions have undefined behaviour since you are modifying string literals. It just seems to work in one case. Basically, result needs to point to memory that can be legally accessed, which is not the case in either of the snippets.
On the same subject, you might find this useful: What Every C Programmer Should Know About Undefined Behavior.
Think of it this way.
When you say
char* result = "";
you are setting up a pointer 'result' to point to a 1-byte null terminated string (just the null). Since it is a local variable it will be allocated on the stack.
Then when you say
*result++ = c;
you are storing that value 'c' in to that address + 1.
So, where are you putting it?
Well, most stacks are to-down; so they grow toward lower addresses; so, you are probably writing over what is already on the stack (the return address for whatever called this, all the registers it needs restore and all sorts of important stuff).
That is why you have to be very careful with pointers.
When you expect to return a string from a function, you have two options (1) provide a string to the function with adequate space to hold the string (including the null-terminating character), or (2) dynamically allocate memory for the string within the function and return a pointer. Within your function you must also have a way to insure your are not writing beyond the end of the space available and you are leaving room for the null-terminating character. That requires passing a maximum size if you are providing the array to the function, and keeping count of the characters read.
Putting that together, you could do something similar to:
#include <stdio.h>
#define MAXC 256
char* getLine (char *s, int max)
{
int i = 0, c = 0;
char *p = s;
while (i + 1 < max && (c = getchar()) != '\n' && c != EOF) {
*p++ = c;
i++;
}
*p = 0;
return s;
}
int main (void) {
char buf[MAXC] = {0};
printf ("\ninput : ");
getLine (buf, MAXC);
printf ("output: %s\n\n", buf);
return 0;
}
Example/Output
$ ./bin/getLine
input : A quick brown fox jumps over the lazy dog.
output: A quick brown fox jumps over the lazy dog.
Im having some trouble writing a getstring function, this is what I have so far.
Regards,
V
const char* getstring()
{
char *buffer;
int i = 255;
buffer = (char *)malloc(i*sizeof(char));
*buffer = getchar();
while ( *buffer != '\n' )
{
buffer++;
*buffer = getchar();
}
*buffer = '\0';
const char* _temp = buffer;
return _temp;
}
int main()
{
char* temp = getstring();
for ( ;temp++ ; *temp != '\0')
{
printf("%c", *temp);
}
return 0;
}
You're setting _temp to buffer when the latter points at the terminating '\0' of the string.
Move the line:
const char* _temp = buffer;
to be immediately after the line:
buffer = (char *)malloc(i*sizeof(char));
so that _temp is pointing to the start of the buffer.
You have some other problems:
Don't use the name _temp - names with a leading underscore are reserved;
You need to test that you don't write more than i bytes into the buffer;
You should test for malloc() returning NULL;
You need to test for getchar() returning EOF. This will mean you need to store the getchar() result in a variable of type int before you assign it to *buffer;
As Michael Mrozek points out in a comment, the expressions in your for loop are the wrong way around.
...and as a point of style, sizeof(char) is always 1, so multiplying by it is unnecessary; and casting the result of malloc() is unnecessary in C and considered undesirable (unlike C++, where it is required).
Why not just use
char buffer[255];
scanf("%254s", &buffer);
or
char* buffer = readline("GO GO GO:");
const char* _temp = buffer;
Move the above statement just after the call to malloc
Important:
Free the memory allocated to buffer after its use in main().
free(temp);
You need to keep track of the allocated pointer - the value returned by malloc() - immediately after calling malloc() so you can pass it back to the caller. You should also check for EOF as well as newline - and that requires an int (not a char) to hold the value from getchar(). At minimum!