does the pointer reallocate memory as it increments? - c

how can i stop *str from filling memory that i didnt give to it, without having to add an ending condition which in this case is : i <= n
do{
//instructions;
} while (... && i <= n);
in this exemple i reserved only 3 bytes of memory to *str but when i run my code and input more than 3 characters it still works... how does that happen shouldnt it give an error cuz there isnt enough memory for the rest of the characters ? what if the selected empty adresses were xxxxx1 xxxxx2 xxxxx3 and then xxxxx4 is full will it stop and output only the 3 characters without an error ?
P.s : I am aware of the function gets() but i dont want to use it because it reallocates memory. i thought that by entering character by character i will solve the problem and stop the user from filling the pointer because this time there is no memory reallocation and *str only has 3 blocks of memory so the rest will go to the buffer and *str will stop at *(str + 2)
hope u understood the problem and thank u for answering
#include <stdio.h>
#include <string.h>
#include <malloc.h>
int main()
{
int i = -1, n = 3;
char *str = (char *)malloc(n*sizeof(char));
printf("Enter a string: ");
do
{
i++;
str[i] = getchar();
} while (str[i] != '\n' && i < n);
str[i] = '\0';
printf("Entered string is: %s", str);
return 0;
}

C doesn't perform any type of bounds checking on arrays or allocated memory. That's part of what makes it fast.
That also means that reading or writing past the end of an array causes undefined behavior which basically means there's no guarantee what the program will do. The language trusts you to do the proper thing, so it's up to you to ensure that you don't do something you shouldn't.
Also, gets doesn't reallocate memory. In fact, it shouldn't be used at all specifically because it doesn't perform any bounds checking.

Your example doesn't work if the input string is longer than two characters since it then tries to write beyond the array. What will happen when you try to write outside of the array is undefined, which means that it may work by pure chance under some circumstances. Try this safe function instead which always reads the entire line and truncates the result if necessary:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ReadLine(char result[], int resultLen)
{
int ch, i;
assert(resultLen > 0);
i = 0;
ch = getchar();
while ((ch != '\n') && (ch != EOF)) {
if (i < resultLen - 1) {
result[i] = ch;
i++;
}
ch = getchar();
}
result[i] = '\0';
}
int main(void)
{
int n = 3;
char *str = malloc(n);
printf("Enter a string: ");
ReadLine(str, n);
printf("Entered string is: %s\n", str);
free(str);
return 0;
}

Related

'SER_' or '_' character appearing in end of (string)output in c

I am trying to print each word in a single line of a given sentence. It worked perfectly fine but a '_' appears in end of line. please help me with it and also proper manar to write it.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
char *s,i,check=0;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
for(i=0;i<1024;i++ ||check<=2)
{
if(*(s+i)!=' ')
{
printf("%c",*(s+i));
check=0;
}
else
{
printf("\n");
check++;
}
// fflush(stdin);
}
return 0;
}
Output:
dkf fja fjlak d
dkf
fja
fjlak
d SER_
Output2:
-for(i=0;i<20;i++ ||check<=2)-
hello I am suraj Ghimire
hello
I
am
suraj
Ghi
I am not sure your code works as you say..
The type of i is not a char *, so it should be int.
You process the input string without considering the NULL terminating char, which leads to a lot of garbage prints.
You do not release allocated memory.
I suggest this slightly modified version:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
char *s, *p;
/* Allocate a new string and verify the allocation has succeeded. */
s = malloc(1024 * sizeof(char));
if (!s) {
printf("malloc failed\n");
return 1;
}
/* Read from user. */
scanf("%[^\n]", s);
/* Work on a copy of `s` (must simpler and faster than a indexed access). */
p = s;
while (*p) {
if (*p != ' ') {
printf("%c",*p);
}else{
printf("\n");
}
p++;
}
free(s);
return 0;
}
Example output:
$ ./a.out
abc def gh i j kmlm opqrst
abc
def
gh
i
j
kmlm
opqrst
EDIT: As requested by the OP, further details regarding the NULL terminating char.
By convention, strings (array of characters) end with a specific character which we call the NULL terminating char. This character is 0 and marks the end of the string data.
In your example, the buffer which store the string is dynamically allocated in RAM. If you do not check for the NULL terminating character of the string, then you keep processing data as if it is part of the string (but it is not).
Going beyond this character make you access the following memory data (which is part of your program RAM data). Since these data can be anything (ranging from 0 to 255), printing them may lead to "gibberish" because they may not be printable and are definitely not consistent with your string.
In the "best" case the program halts with a "segmentation fault" because you are accessing a memory region you are not allowed to. In the "worst" case you print a lot of things before crashing.
This is typically called a data leak (whether it is RAM or ROM) because it exposes internal data of your program. In the specific case of your example there no sensitive data. But! Imagine you leak passwords or private keys stored in your program .. this can be a severe security issue!
There are a couple issues with your code.
Firstly, you need to check that the for loop does not exceed the bounds of the string.
Your for loop is always set to true because the logical OR operator || has a higher precedence than the comma operator. Because of this the loop will always run unless it gets stopped with break
Lastly your check is never reset to 0 after it reaches a value of 2.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *s,i,check=0;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
for(i=0; i<strlen(s); i++) {
if(*(s+i) != ' ') {
printf("%c",*(s+i));
check=0;
} else {
printf("\n");
check++;
if (check > 2) break;
}
}
return 0;
}
Output:
Hello, this is a test
Hello,
this
is
a
test
for(i=0;i<1024;i++ ||check<=2)
There are two issues. One is length of string won't always be 1024, so it might be good to determine the length of string before print the string. The other is check<=2, which have to put in the second part of the for loop, so the test will be evaluated. Also it is better to calculate the length of string once. So I store the length of string in len.
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s, i, check = 0;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
size_t len = strlen(s);
for (i = 0; i < len || check <= 2; i++) {
if (*(s + i) != ' ') {
printf("%c", *(s + i));
check = 0;
} else {
printf("\n");
check++;
}
// fflush(stdin);
}
return 0;
}

If i input too many characters my program either has a 'mremap_chunk(): invalid pointer' or a 'realloc(): invalid old size'

my program was built as a test to input as many sentences as the user want (until he enters -1), and then concatenate all sentences (\n included). If i input some characters is fine, but if i input more then 25 characters i have the two errors listed above, i tried simulating what would happen in paper and i can´t find the problem, help is appreciated, thanks in advance.
The code is displayed below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char *s = malloc(1), *sentence = malloc(0);
int sSize = 0;
printf("Insert sentences, press '-1' if you want to exit:\n");
do
{
fgets(s,100,stdin);
if(strcmp(s,"-1\n") != 0)
{
sSize += strlen(s);
sentence = realloc(sentence, sSize * sizeof(char));
//s[strcspn(s, "\0")] = '\n';
strcat(sentence, s);
}
}while(strcmp(s,"-1\n") != 0);
printf("==================sentence================\n");
printf("%s", sentence);
return 0;
}
This is a classic buffer overrun problem:
s = malloc(1) - s now points to a one-character buffer.
fgets(s,100,stdin); - reads up to 100 characters into s - which is a one-character buffer.
EDIT
Here's a version which works and doesn't use a separate "sentence buffer":
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
const char *terminator = "-1\n";
char *sentences = malloc(100);
char *pNext_sentence;
printf("Insert sentences, press '-1' if you want to exit:\n");
*sentences = '\0';
do
{
sentences = realloc(sentences, strlen(sentences)+100);
pNext_sentence = sentences + strlen(sentences);
fgets(pNext_sentence, 100, stdin);
} while(strcmp(pNext_sentence, terminator) != 0);
*(sentences + (strlen(sentences) < strlen(terminator) ? 0 : strlen(sentences) - strlen(terminator))) = '\0';
printf("==================sentences================\n");
printf("%s", sentences);
free(sentences);
return 0;
}
You must use reallocate memory with realloc before using fgets, which, in your case, reads 100 bytes.
Your string has the initial size of 1.

function call in do while loop only execute once.

I had a program to check user input and make sure it's only integer and not character. In my main function, do while loop only executes once when the input is incorrect. But I want it to keep it executing until the user enter a valid input. My doAgain() function is to ask if the user want to Try again or not. The problem is with doAgain() function. It only executes once if leave it in the if statement. Everything works fine except this glitch. However, when i remove it, the loop keep executing until the user enter valid input like i wanted it to, but then doAgain() function would be useless
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* get boundary */
char* getBoundary(char str[]){
int i;
char c;
str = (char*) malloc(sizeof(char));
for (i = 0; (c = getchar()) != '\n'; i++) // The loop stop running after the second time
{
str = (char *) realloc(str, sizeof(char) + i);
str[i] = c;
}
str[i] = '\0';
return str;
}
/* check for valid string */
int checkStr(const char *check)
{
unsigned i;
size_t len = strlen(check);
for (i = 0; i < len; i++)
if(isalpha(check[i]))
{
printf("Invalid integer formatt!!!");
return 0;
}
return 1;
}
/* Ask if do again */
int doAgain(void)
{
char ans, c;
do {
printf("Do you want to try again?: ");
scanf(" %c", &ans);
switch (ans)
{
case 'y':
case 'Y':
case 'n':
case 'N':
return (ans == 'y') || (ans == 'Y') ? 1 : 0;
break;
default:
printf("Invalid answer!!! answer 'y' and 'Y' or 'n' and 'N' only\n");
do { /* flush input stream */
c = getchar();
}while (c != '\n');
}
}while (1);
}
/* Main */
int main(void)
{
char *l_boundRow;
l_boundRow = NULL;
do {
printf("Enter lower bound row: ");
l_boundRow = getBoundary(l_boundRow);
if (!checkStr(l_boundRow) && doAgain()) // problem start here, it works if I remove doAgain() function
continue; // if the string is invalid, the program asks user if they want to try again
else
break;
}while (1);
free(l_boundRow);
return 0;
}
Revised answer
The immediate problem is that when doAgain() exits with y or n, it doesn't read the newline after those characters, so when it re-enters getBoundary(), the first character it reads is whatever was after the y or n which was probably a newline, which terminates the input line. You need to gobble the rest of the line on a valid input as well as on the invalid ones.
This code mostly works — it is leak free, too (at least under my casual testing).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char* getBoundary(void);
int checkStr(const char *check);
int doAgain(void);
/* get boundary */
char* getBoundary(void)
{
int i;
int c;
char *str = (char*) malloc(sizeof(char));
for (i = 0; (c = getchar()) != '\n' && c != EOF; i++)
{
str = (char *) realloc(str, 2 + i);
str[i] = c;
}
str[i] = '\0';
return str;
}
/* check for valid string */
int checkStr(const char *check)
{
unsigned i;
size_t len = strlen(check);
for (i = 0; i < len; i++)
{
if (!isdigit(check[i]))
{
printf("Invalid integer format (%s)!!!\n", check);
return 0;
}
}
return 1;
}
static int gobble(void)
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
return c;
}
/* Ask if do again */
int doAgain(void)
{
char ans;
int c;
do {
printf("Do you want to try again?: ");
scanf(" %c", &ans);
switch (ans)
{
case 'y':
case 'Y':
c = gobble();
return 1;
case 'n':
case 'N':
c = gobble();
return 0;
default:
{
printf("Invalid answer!!! answer 'y' and 'Y' or 'n' and 'N' only\n");
c = gobble();
if (c == EOF)
{
printf("EOF detected\n");
return 0;
}
}
}
} while (1);
}
/* Main */
int main(void)
{
char *l_boundRow;
l_boundRow = NULL;
do {
printf("Enter lower bound row: ");
l_boundRow = getBoundary();
if (checkStr(l_boundRow))
break;
if (!doAgain())
break;
free(l_boundRow);
}while (1);
printf("Final bound row: %s\n", l_boundRow);
free(l_boundRow);
return 0;
}
If you select not to try again after an invalid input, the last invalid value is printed as the 'Final bound row'. You can easily hack the code to avoid that problem.
Incidentally, when I first compiled your code, I only got 3 warnings from it under my default stringent options — because I demand prototypes before (non-static) function definitions. That's extremely good; well done. Few people write code that's posted on SO that passes that level of scrutiny with as few complaints.
If it were my code, I would have few if any do … while loops (none in this code). They are occasionally useful, but occasionally is the operative term. Generally, it is best to use a top-testing while loop, or an explicit for loop.
Original answer
A real problem, but not the one immediately causing trouble.
In the code in getBoundary(), you first allocate one character. Then, in the body of the loop, you reallocate i + 1 characters. On the first iteration, you reallocate 1 byte; then 2, etc. And then when you exit the loop, you write one beyond the last character that was allocated, which leads to undefined behaviour. You need to use i + 2 as the size to reallocate. (There are those who'd rail against you for using sizeof(char) since that is guaranteed to be 1.)
That is probably the source of your trouble; writing beyond the end of an allocated buffer can easily lead to crashes.
If you ran the code under valgrind, it would tell you about this mistake.
Separately, it is not a good idea to allocate one more byte each time around the loop. It would be better to allocate, say, 20 bytes (big enough to hold any 64-bit integer value), or to double the size on each iteration when you need more space. It isn't going to be time critical in this context, but it can become a problem in bigger programs.
Note too that your checkstr() function only detects alpha characters; punctuation and control characters will also not convert to an integer. You should check that each character is a digit (isdigit(check[i])), and you might have to worry about plain char being signed — so isdigit((unsigned char)check[i]) is better still. Similar comments apply to the other isuvwxyz() functions.
In doAgain(), you should use int c; instead of char c; and you should check for EOF as well as newline. If you detect EOF, the answer is 'no' and you should return that.
Also, in your getBoundary() function again, you have:
str = (char *) realloc(str, sizeof(char) + i);
There are those who would castigate you for the cast; I am not of the mindset that does that. But be aware that you will get criticism for doing so from many people who answer questions on C at SO.
More significantly, you should not write the realloc() code this way. The idiom:
ptr = realloc(ptr, new_size);
leaks memory if the allocation fails. You've just had the only pointer to the memory wiped out with NULL, even though realloc() promises that it did not free the old memory. You should use:
void *new_ptr = realloc(ptr, new_size);
if (new_ptr == NULL)
…handle out of memory condition…ptr is still valid!
ptr = new_ptr;
You should also always check that memory allocations succeed. If they fail, you end up dereferencing a null pointer, which leads to crashes.

read string of character and assign it to an array

I don't know how to work with scanf and get the input of it for the entry of the function readBigNum I want to make array until the user entered the Enter and also I want to write a function for assigning it into an array and return the size of the large number
I want readBigNum to exactly have the char *n but I can not relate it in my function
#include <stdio.h>
int readBigNum(char *n)
{
char msg[100],ch;
int i=0;
while((ch=getchar())!='\n')
{
if(ch!='0'||ch!='1'||ch!='2'||ch!='3'||ch!='4'||ch!='5'||ch!='6'||ch!='7'||ch!='8'||ch!='9')
return -1;
msg[i++]=ch;
}
msg[i]='\0';
i=0;
return i;
}
int main()
{
const char x;
const char n;
n=scanf("%d",x);
int h=readBigNum(&n);
printf(h);
}
If I understand your question correctly, you want to implement a function that will read numbers from stdin storing them in a buffer. If a non-number is encountered, you want to return -1. If a new-line is encountered, you want to return the number of characters that were read. If that's correct, you'll probably want your code to look something like the following:
#include <stdio.h>
int readBigNum(char* n)
{
char ch;
int i=0;
while ((ch = getchar()) != '\n') {
if (ch < '0' || ch > '9') {
return -1;
}
n[i++] = ch;
}
n[i] = '\0';
return i;
}
int main(void) {
char buf[100];
int bytes = readBigNum(buf);
printf("%s\n", buf);
printf("%d\n", bytes);
};
The main differences from your implementation
The array to be populated is initialized in main and passed to the readBigNum function. This is a little simpler than having the function control the memory, in which case you would need likely need to deal with malloc and free. Even with this, you run the risk of a buffer overrun and will likely want to take additional precautions to prevent that.
The function does not set i to 0 before returning it. The original code could never return a value other than -1 (on error) or 0, which didn't appear to be the intent.
This code doesn't use scanf. Given your description of what you wanted to accomplish, using scanf didn't appear to be a good fit, however if you provide more information on why you were calling it might help to inform this answer.
The printf call was incorrect, it has been updated to print the number of bytes returned, and an additional printf call was added to print the updated buffer.
Remember that getchar() returns type int, not char. This is because the function may return EOF (which is defined as a negative integer with no particular value).
Also, for functions that deal with buffers, it is always a good idea to take an extra argument that describes the size of the array. This helps reduce buffer overruns because you know how far you can go. With your existing function, if the user types more than 100 characters, your buffer is overrun.
#include <stdio.h>
#include <ctype.h>
int readBigNum(char *n, size_t len)
{
int ch;
int i = 0;
// we make sure 'i' is less than 'len - 1' to leave space for '\0'
while((ch = getchar()) != EOF && i < (len - 1))
{
if (ch == '\n') // stop on linefeed
break;
else if (!isdigit(ch))) // abort on invalid character
return -1;
else
n[i++] = (char) ch;
}
msg[i] = '\0';
return i;
}
int main(void)
{
char buf[100];
int result = readBigNum(buf, sizeof buf);
if (result > 0)
printf("Length %d : %s\n", result, buf);
else
printf("Invalid number!\n");
}

C - Malloc issue (maybe something else)

Update edition:
So, I'm trying to get this code to work without using scanf/fgets. Gets chars from the user, puts it into a pointer array using a while loop nested in a for loop.
#define WORDLENGTH 15
#define MAXLINE 1000
int main()
{
char *line[MAXLINE];
int i = 0;
int j;
int n;
char c;
for (n=0; c!=EOF; n){
char *tmp = (char *) malloc(256);
while ((c=getchar())!=' '){
tmp[i]=c; // This is no longer updating for some reason.
i++;
}
line[n++]=tmp; //
i=0;
printf("\n%s\n",line[n]); //Seg fault here
}
for(j = 0; j (lessthan) n; j++){
printf("\n%s\n", line[j]);
free (line[j]);
}
return 0;
So, now I'm getting a seg fault. Not sure why tmp[i] is not updating properly. Still working on it.
I've never learned this much about programming during the entire semester so far. Please keep helping me learn. I'm loving it.
You print line[i] and just before that, you set i to 0. Print line[n] instead.
Also, you forgot the terminating 0 character. And your code will become easier if you make tmp a char array and then strdup before assigning to line[n].
sizeof(WORLDLENGTH), for one, is wrong. malloc takes an integer, and WORLDLENGTH is an integer. sizeof(WORLDLENGTH) will give you the size of an integer, which is 4 if you compile for a 32-bit system, so you're allocating 4 bytes.
Btw - while ((c=getchar())!=' '||c!=EOF) - what's your intent here? A condition like (a!=b || a!=c) will always return true if b!=c because there is no way a can be both b and c.
And, as others pointed out, you're printing out line[i], where i is always 0. You probably meant line[n]. And you don't terminate the tmp string.
And there's no overflow checking, so you'll run into evil bugs if a word is longer than WORDLENGTH.
Others have already told you some specific problems with your code but one thing they seem to have missed is that c should be an int, not a char. Otherwise the comparison to EOF wil not work as expected.
In addition, the segfault you're getting is because of this sequence:
line[n++]=tmp;
printf("\n%s\n",line[n]);
You have already incremented n to the next array element then you try to print it. That second line should be:
printf("\n%s\n",line[n-1]);
If you just want some code that works (with a free "do what you darn well want to" licence), here's a useful snippet from my code library.
I'm not sure why you think fgets is to be avoided, it's actually very handy and very safe. I'm assuming you meant gets which is less handy and totally unsafe. Your code is also prone to buffer overruns as well, since it will happily write beyond the end of your allocated area if it gets a lot of characters that are neither space nor end of file.
By all means, write your own code if you're educating yourself but part of that should be examining production-tested bullet-proof code to see how it can be done. And, if you're not educating yourself, you're doing yourself a disservice by not using freely available code.
The snippet follows:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
// Test program for getLine().
int main (void) {
int rc;
char buff[10];
rc = getLine ("Enter string> ", buff, sizeof(buff));
if (rc == NO_INPUT) {
printf ("No input\n");
return 1;
}
if (rc == TOO_LONG) {
printf ("Input too long\n");
return 1;
}
printf ("OK [%s]\n", buff);
return 0;
}
It's a useful line input function that has the same buffer overflow protection as fgets and can also detect lines entered by the user that are too long. It also throws away the rest of the too-long line so that it doesn't affect the next input operation.
Sample runs with 'hello', CTRLD, and a string that's too big:
pax> ./qq
Enter string> hello
OK [hello]
pax> ./qq
Enter string>
No input
pax> ./qq
Enter string> dfgdfgjdjgdfhggh
Input too long
pax> _
For what it's worth (and don't hand this in as your own work since you'll almost certainly be caught out for plagiarism - any half-decent educator will search for your code on the net as the first thing they do), this is how I'd approach it.
#include <stdio.h>
#include <stdlib.h>
#define WORDLENGTH 15
#define MAXWORDS 1000
int main (void) {
char *line[MAXWORDS];
int numwords = 0; // Use decent variable names.
int chr, i;
// Code to run until end of file.
for (chr = getchar(); chr != EOF;) { // First char.
// This bit gets a word.
char *tmp = malloc(WORDLENGTH + 1); // Allocate space for word/NUL
i = 0;
while ((chr != ' ') && (chr != EOF)) { // Read until space/EOF
if (i < WORDLENGTH) { // If space left in word,
tmp[i++] = chr; // add it
tmp[i] = '\0'; // and null-terminate.
}
chr = getchar(); // Get next character.
}
line[numwords++] = tmp; // Store.
// This bit skips space at end of word.
while ((chr == ' ') && (chr != EOF)) {
chr = getchar();
}
}
// Now we have all our words, print them.
for (i = 0; i < numwords; i++){
printf ("%s\n", line[i]);
free (line[i]);
}
return 0;
}
I suggest you read that and studdy the comments so that you know how it's working. Feel free to ask any questions in the comments section and I'll answer or clarify.
Here's a sample run:
pax$ echo 'hello my name is pax andthisisaverylongword here' | ./testprog
hello
my
name
is
pax
andthisisaveryl
here
Change your printf line - you need to print line[n] rather than line[i].
first your malloc formula is wrong
malloc(sizeof(char)*WORDLENGTH);
you need to allocate the sizeof a char enought times for the lenght of your word (also 15 seems a bit small, your not counting the longest word in the dictionnary or the "iforgettoputspacesinmyphrasestoscrewtheprogrammer" cases lol
don't be shy char is small you can hit 256 or 512 easily ^^
also
printf("\n%s\n",line[i]);
needs to be changed to
int j = 0;
for(j=0;j<i;j++){
printf("\n%s\n",line[j]);
}
your i never changes so you always print the same line

Resources