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;
}
Related
I'm still a newbie to C so please forgive me if anything below is wrong. I've searched this up online but nothing really helped.
Right now, I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void appendStr (char *str, char c)
{
for (;*str;str++); // note the terminating semicolon here.
*str++ = c;
*str++ = 0;
}
int main(){
char string[] = "imtryingmybest";
char result[] = "";
for(int i = 0; i < strlen(string); i++){
if(i >= 0 && i <= 3){
appendStr(result, string[i]);
}
}
printf("%s", result);
}
Basically, I'm trying to add the first 4 characters of the String named string to result with a for loop. My code above did not work. I've already tried to use strcat and strncat and neither of them worked for me either. When I used
strcat(result, string[i]);
It returns an error saying that the memory cannot be read.
I know that in this example it might have been easier if I just did
appendStr(result, string[0]);
appendStr(result, string[1]);
appendStr(result, string[2]);
appendStr(result, string[3]);
But there is a reason behind why I'm using a for loop that couldn't be explained in this example.
All in all, I'd appreciate it if someone could explain to me how to append individual characters to a string in a for loop.
The following code doesnt use your methods but successfully appends the first 4 chars to result
#include <stdio.h>
#include <string.h>
int main()
{
// declare and initialize strings
char str[] = "imtryingmybest";
char result[5]; // the 5th slot is for \0 as all strings are null terminated
// append chars to result
strncat(result, str, 4);
// ^ ^ ^
// | | |- number of chars to be appended
// | | - string to be appended from
// | - string to append to
// print string
printf("result: %s\n", result);
return (0);
}
The result of the above is as wanted:
>> gcc -o test test.c
>> ./test
result: imtr
Let me know if anything is not clear so i can elaborate further
string was ruined by the overflow of result buffer.
appendStr can be executed only once. next time strlen(string) will return 0. because *str++ = 0; has been written to the space of string.
result buffer has only 1 byte space, but you write 2 byte to it in appendStr call.
the second byte will ruin string space.
I suggest debug with gdb.
try to get rid of Magic numbers
#define BUFF_SIZE 10 // define some bytes to allocate in result char array
#define COPY_COUNT 4 // count of chars that will be copied
int main(){
char string[] = "imtryingmybest";
char result[BUFF_SIZE] {}; // allocate some chunk of memory
for(size_t i = 0; i < strlen(string); i++){
if(i < COPY_COUNT){
appendStr(result, string[i]);
}
}
printf("%s", result);
}
I showed the solution code Paul Yang showed the problem
As others have pointed out the code has a simple mistake in the allocation of the destination string.
When declaring an array without specifying its size, the compiler deduces it by its initializer, which in your case means a 0 + the NULL character.
char result[] = ""; // means { '\0' };
However, I think that the bigger issue here is that you're effectively coding a Schlemiel.
C strings have the serious drawback that they don't store their length, making functions that have to reach the end of the string linear in time complexity O(n).
You already know this, as shown by your function appendStr()
This isn't a serious issue until start you appending characters or strings in a loop.
In each iteration of your loop appendStr() reaches the last character of the string, and extends the string, making the next iteration a little slower.
In fact its time complexity is O(n²)
Of course this is not noticeable for small strings or loops with few iterations, but it'll become a problem if the data scales.
To avoid this you have to take into account the growing size of the string.
I modified appendStr() to show that now it starts from the last element of result
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void appendStr (char *str, char c, char *orig)
{
printf("i: %ld\n", str - orig);
for (; *str; str++); // note the terminating semicolon here.
*str++ = c;
*str++ = 0;
}
int main()
{
char string[32] = "imtryingmybest";
char result[32] = "";
for(int i = 0; i < strlen(string); i++) {
if(i >= 0 && i <= 3) {
// I'm passing a pointer to the last element of the string
appendStr(&result[i], string[i], result);
}
}
printf("%s", result);
}
You can run it here https://onlinegdb.com/HkogMxbG_
More on Schlemiel the painter
https://www.joelonsoftware.com/2001/12/11/back-to-basics/
https://codepen.io/JoshuaVB/pen/JzRoyp
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.
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;
}
I am writing a code that takes a string as input and prints every word in the string in a newline.
I am using pointer arithmetic for this purpose
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
while (*s != '\0') {
if (*s == ' ') {
printf("\n");
} else {
printf("%s", s);
}
s++;
}
return 0;
}
Input:
i am a beginner. \n
Output:
i am a beginner \n
am a beginnerm a beginner \n
a beginner \n
beginnereginnerginnerinnernnernererr
Instead of %s you need %c to print a single character. Besides that, you don't need to free the memory you get from malloc since realloc takes care of that, but you have to free the memory you got from realloc. Yes, the OS will clean up after you, but it is best to release the resources you acquired. In order to do the free we are going to not change the value of s, instead we are going to copy it. Here is the fixed version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char* s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
char* p = s = realloc(s, strlen(s) + 1);
while (*p != '\0') {
if (*p == ' ') {
printf("\n");
} else {
printf("%c", *p);
}
++p;
}
free(s);
return 0;
}
Input:
My awesome input
Output:
My
awesome
input
A few points for you to consider. If the user adds multiple space characters in between words or adds something like '\t', your program doesn't handle the case correctly.
I would say its not very logical to reinvent the wheel unless you need some extra functionality or portability. Same can be done more reliably like:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
char *to_free = s = realloc(s, strlen(s) + 1);
char *word;
while ((word = strsep(&s, " \t")) != NULL)
printf("%s\n", word);
free(to_free);
return 0;
}
This also allows you to keep track of tabs as well as spaces(as you are considering words). Notice the argument passed to strsep, its a space and a tab. You could easily separate words using ,, . etc as well by just adding these delimeters to the strsep argument.
Also it is a good practice to free the memory you allocated.
if you use printf with "%s" it prints out the entire string all the way to \0.
that's why you see the entire sentence in every line (minus a few characters from the start).
the way you used pointers in this code, I'm guessing you're trying print out individual characters, so just switch "%s" with "%c"
Below is the code I have so far. It is giving segmentation fault after a couple of iterations. Can anyone help me to figure out the problem?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *str; // 1GB = 1073741824 bytes
char *temp;
long long int i;
str = (char *)malloc(1073741824);
strcpy(str,"a");
for(i = 1; i <= 73741824;i = i*2)
{
strcat(str,str);
}
free(str);
}
You are calling strcat() with the same string as both arguments, which is an error. See the manual page:
The strings may not overlap, and the dest string must have enough space for the result.
You're experiencing some undefined behavior! If you read the description of strcat, it mentions: "If copying takes place between objects that overlap, the behavior is undefined," (source).
If you think about it, it first copies the first byte of str to the null byte of str, and continues until the null byte. Do you see the problem? You overwrite it, so you will keep copying bytes until you encounter a garbage null byte.
The way around this is to not have the same source and destination string. Also, why are you iterating until 73741824? If you want a 1GB string, you should iterate until 1073741824. Also keep in mind building the string this way is no more efficient than just concatenating "a" onto your string ~1 billion times. Knowing that, that's what we'll end up doing to solve our problem.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *str; // 1GB = 1073741824 bytes
char *temp;
long long int i;
const size_t GB = 1073741824;
str = (char *)malloc(GB);
strcpy(str, "a");
for(i = 1; i < GB; i++) {
strcat(str + i, "a");
}
free(str);
}
Edit: if you prefer the original algorithm, I've fixed that as well. Just make the corresponding changes. This will avoid copying to any overlapping memory, and therefore, avoid any undefined behavior.
for(i = 1; i < GB; i *= 2) {
str[i - 1] = '\0';
strcat(str + i, str);
str[i - 1] = 'a';
str[2 * i - 1] = 'a';
str[2 * i] = '\0';
}
I thought this one should be closed, since the "what happens if string is concatened to itself" question is already answered here: Concatenating string with itself two times give segmentation fault.
However, since the close vote was rejected and there are number of other issues, I've fixed the code. This algorithm uses 2*SIZE memory, but it's significantly faster than the one in kamoroso94's answer (which uses less memory) and remains closer to the question author's idea.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE (1024 * 1024 * 1024) // convenient way how to define 1GB
int main()
{
char *str;
char *temp;
long long int i;
// don't forget to allocate space for the terminating character!
str = malloc(SIZE + 1); // no need to typecast the result malloc()
temp = malloc(SIZE + 1);
// don't forget to check for allocation failures
if (str == NULL || temp == NULL) {
printf("malloc failed\n");
return -1;
}
strcpy(temp, "a");
for(i = 1; i <= SIZE; i *= 2) {
// concatenate the buffer to the string
strcat(str, temp);
// copy the whole string to the temporary buffer
strcpy(temp, str);
}
printf("length of s = %u\n", strlen(str));
free(str);
free(temp);
}