I'm trying to solve a code to strip a sentence down only to it's alpha character, using the following code, but the code always gives me a runtime error(The commented parts are steps I had taken to figure out the solution).
[Ex: Test'sen- tence should print Testsentence]
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUFFER_LEN 1000
#define BUFFER_INCR 15
int main(void)
{
int buffer_length = BUFFER_LEN;
char *pString = malloc(BUFFER_LEN);/* initial array */
char *pTemp_start = pString;
long long int String_len = 0;
char *pTemp = NULL;
int copy = 0;
int count = 0;/*delete this after check*/
while((*pString++ = getchar()) != '\n')
{
String_len = pString - pTemp_start;
printf("\nThe character you inputted is: %c", *(pString+count++));
//getchar();
if(String_len == (buffer_length - 1))/*reserve one for newline*/
{
buffer_length += BUFFER_INCR;
pTemp = realloc(pString, buffer_length);/*reallocate space for
15 more chars.*/
pTemp_start = pTemp - String_len;
pString = pTemp;
free(pTemp);
pTemp = NULL;
if(!pString)
{
printf("The space couldn't be allocated");
return 1;
}
}
}
/*checks that can be done for addresses*/
//printf("\nThe length of the string is: %lld", pString - pTemp_start);
*(--pString) = '\0';
//printf("\nThe charcter at the end is: %d", *(pString + String_len - 1));
//printf("\nThe character at the mid is: %d", *(pString + 2));
printf("The input string is: %c", *pString);
/*code to remove spaces*/
for(int i = 0; i < (String_len + 1); i++)
{
if((isalnum(pString[i])))
{
*(pString + copy++) = *(pString +i);
}
}
*(pString + copy) = '\0';/*append the string's lost null character*/
printf("\nThe stripped string is: \n%s", pString);
return 0;
}
The code simply doesn't print anything that's inputted.
So you've got a conflict in your code between this line
while((*pString++ = getchar()) != '\n')
and lines like the following.
pTemp = realloc(pString, buffer_length);
The first line I've quoted is incrementing the position of pString within your allocated memory, but the second one is acting as if pString is still pointing to the start of it. realloc() won't work unless pString is pointing to the start of the allocated memory. You're then not checking the results of the realloc() call, assigning the new memory block to pString and then freeing the newly allocated memory. So you're definitely going to have unexpected results.
You also have to remember that stdin is buffered, so your code will wait until it's got an entire line to read before doing anything. And stdout is also buffered, so only lines that end in a \n will be output. So you probably want to have the following...
printf("The character you inputted is: %c\n", *pString);
...or something similar bearing in mind the issues with how you're using pString.
realloc(pString,...) does not add an allocated block, it replaces the one being reallocated (in this case, pString). So pString isn't (necessarily) a valid pointer after that call. Worse, you then free(pTemp), so you no longer have anything allocated.
Related
I have a bigger string and I want to add the \0 character before a specific string is contained.
ex:
inputString = "some2.text.here"; => outputText = "some2";
I manage to find the last position of the output text, I don't know how to add \0 and make the pointer end here.
void test()
{
char* str = "some2.text.here";
char* search = ".text.here";
char * new;
//size text to be removed
int lengthOfStr = 10; //search length
int size = 0;
char stringEnding = '\0';
char * newPath;
new = '\0';
for(int i = 0; i < 200; i++){
if(*(str + i) == '\0'){
printf("found on index %d", i);
printf("\n i: %d \n lengthOfStr : %d", i, lengthOfStr);
new = (char *) malloc(i - lengthOfStr);
memcpy(new, str, sizeof(i - lengthOfStr));
break;
}
}
printf("\n string value : %s", new);
}
Here I try to copy a specific length but is not working well... I also tried to add str[5] = '\0'but also did not did the trick... Any tips?
There seems to be 3 problems.
Too little memory allocated
Wrong number of bytes copied
Missing string termination
Something like:
new = malloc(i - lengthOfStr + 1); // Allocate 1 more char
memcpy(new, str, i - lengthOfStr); // Correct number of bytes to copy
new[i - lengthOfStr] = '\0'; // Terminate the string
BTW: Your current code always expects the "search" string to be in the end of the current string. Maybe that's what you want but it seems to me that you should use strstr instead of a loop. And... use strlen instead of a hard code length.
I need to take only the odd values from a char array and copy them into correctly sized dynamic memory using a pointer.
However when running my program it works correctly with certain input strings and not with others. Is there something that I'm doing wrong? I can't seem to figure out what's going on.
/* A.) Include the necessary headers in our program */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_LENGTH 32
int main() {
/* B.) Declare char array with inital size of 32 */
char input_string[MAX_STRING_LENGTH];
/* C.) Recieve user input.
Can save the first 31 characters in the array with 32nd reserved for '\0' */
printf("Enter a string of characters: ");
/* D.) Using the technique we discussed to limit the string to 31 charaters */
scanf("%31s", input_string);
printf("\n");
/* Will be used to determine the exact amount of dynamic memory that will be allocated later */
int odd_value_count = 0;
printf("Odd Characters: ");
for(int i = 0; i < strlen(input_string); i++) {
if(i % 2 != 0) {
printf("%c ", input_string[i]);
odd_value_count++;
}
}
printf("\n");
printf("Odd value count: %d\n", odd_value_count);
/* E.) Delecaring the pointer that will hold some part of the input_string
Pointer will be a char type */
char *string_pointer;
/* G.) Allocating the space before the copy using our odd value count */
/* H.) The exact amount of space needed is the sizeof(char) * the odd value count + 1 */
string_pointer = (char *)malloc(sizeof(char) * (odd_value_count + 1));
if (string_pointer == NULL) {
printf("Error! Did not allocte memory on heap.");
exit(0);
}
/* F.) Copying all charcters that are on the odd index of the input_string[] array
to the memory space pointed by the pointer we delcared */
printf("COPIED: ");
for (int i = 0; i < strlen(input_string); ++i) {
if(i % 2 != 0) {
strcpy(string_pointer++, &input_string[i]);
printf("%c ", input_string[i]);
}
}
/* Printing out the string uses the pointer, however we must subtract odd_value_count to
position the pointer back at the original start address */
printf("\n%s\n", string_pointer - odd_value_count);
return 0;
}
This input string: 01030507
works fine and copies & prints: 1357
The input string: testing
Copies etn but prints etng.
I cant figure out why for some strings it prints out the extra character at the end when I never even copy the value over.
You need to Null Terminate your string, like this *string_pointer = '\0';, just after you are done copying the odd characters in your string pointer - after that loop, null terminate your string.
Read more in How to add null terminator to char pointer, when using strcpy?
In the end of your routine you will need to null terminate the string, otherwise you don't have a string you just have a char array, you can use string_pointer which is already pointing to one past the end of the string you want to save:
//...
for (int i = 0; i < strlen(input_string); ++i) {
if(i % 2 != 0) {
strcpy(string_pointer++, &input_string[i]);
//as you are copying characters, you can do this:
//*string_pointer++ = input_string[i];
//instead of strcpy
printf("%c ", input_string[i]);
}
}
*string_pointer = '\0'; // <-- here
//...
I tried to dynamically allocate a string using a function I named ALLO, but when I execute I get an error, which is my function ALLO can't get the string using getc, it gets skipped.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ALLO(char *str){
char c=0;
int i = 0, j = 1;
str = (char*)malloc(sizeof(char));
printf("Enter String : ");
while (c != '\n') {
// read the input from keyboard standard input
c = getc(stdin);
// re-allocate (resize) memory for character read to be stored
str = (char*)realloc(str, j * sizeof(char));
// store read character by making pointer point to c
str[i] = c;
i++;
j++;
}
str[i] = '\0'; // at the end append null character to mark end of string
printf("\nThe entered string is : %s", str);
free(str); // important step the pointer declared must be made free
}
int main(){
char *NomAF;
int NAF;
printf("Entrer le nombre des ateliers : ");
scanf("%d",&NAF);
ALLO(NomAF);
return 0 ;
}
The semantics are wrong.
You ask the user for the names of the athletes, and then you scan it into an integer. You should ask for the number of athletes first. Then, after that, you allocate memory to accommodate each name.
int num_names;
scanf("%d", &num_names);
After you know the number of names, you then allocate a buffer for each name, separately.
char **names;
names = malloc(num_names * sizeof(char **));
for(int i = 0; i < num_names; i++)
ALLOC(&names[i]);
Also, you shouldn't be using scanf for user input. Use fgets instead, which is a little better.
Then, you also should be using a pointer to pointers to get those strings.
A little modified version of your code (which you should review and fix, as needed):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ALLO(char **str){
/* use INT for getc() return */
int c=0, i = 0;
/* you are gettting 1 byte of memory */
*str = malloc(sizeof **str);
/* should use fprintf(stderr...) or fflush(stdout) to guarantee
* the sentence will be seen by user
*/
printf("Enter String : ");
while (c != '\n') {
// read the input from keyboard standard input
c = getc(stdin);
// re-allocate (resize) memory for character read to be stored
/* i = 0 in the first run,
*
* and you have 1 byte alloced in the first run.
*
* so you get 1 byte for actual getc() return
* 1 byte for next character + NULL byte
*
* NOTE: you are STORING the NULL byte in your string. You only
* check for it AFTER you do the assignment, so your strings
* contain a newline before the NULL byte.
*/
*str = (char*)realloc(*str, (i + 2) * sizeof **str);
// store read character by making pointer point to c
(*str)[i] = c;
// you can use only 'i' for this...
i++;
/* #i
*
* Using only 'i' requires that you understand what #i is doing
* during execution. #i will keep the current buffer position,
* and you know you need one more position for the next
* character and one more for the NULL byte.
*
* Therefore, in your realloc statemente, you need #(i + 2)
*/
}
(*str)[i] = '\0'; // at the end append null character to mark end of string
printf("\nThe entered string is : %s", *str);
// if you free here, you can't get the string at #main for printing.
// free is the last step
//free(str); // important step the pointer declared must be made free
}
int main(){
char **NomAF;
int NAF, i;
char buf[100];
printf("Number of athlets : ");
fgets(buf, sizeof(buf), stdin);
NAF = atoi(buf);
NomAF = malloc(NAF * sizeof *NomAF);
// check malloc errors
// get names
for(i = 0; i < NAF; i++) {
ALLO(&NomAF[i]);
printf("New name: %s\n", NomAF[i]);
}
// print names, then free() then
for(i = 0; i < NAF; i++) {
printf("Name: %s\n", NomAF[i]);
free(NomAF[i]);
}
// free the base pointer
free(NomAF);
return 0 ;
}
Add this
while((c=getchar()!='\n')&&c!=EOF);
before getc it skips white space.
Because after this scanf("%d",&NAF); take you are giving input 5(+enter) this goes 5'\n' 5 is got by scanf and '\n' is in buffer and this new line is got by your getc.
and change this str[i] = '\0'; to str[i-1] = '\0';, it replaces the newline with NULL and you allocated memory for i characters only.
You can return the string by return str; and change function return type as char* or if don't want that take a parameter that allocated by malloc.
See this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ALLO(char *str)
{
char c=0;
int i = 0;
printf("Enter String : ");
while (c != '\n')
{
while((c=getchar()!='\n')&&c!=EOF);
c = getc(stdin);
str = (char*)realloc(str, (i+1) * sizeof(char));
if(!str) exit(1);
str[i] = c;
i++;
}
str[i-1] = '\0';
}
int main()
{
char *NomAF;
int NAF;
NomAF=malloc(sizeof(char));
if(!NomAF) exit(1);
printf("Entrer le nombre des ateliers : ");
scanf("%d",&NAF);
ALLO(NomAF);
printf(NomAF);
free(NomAF);
return 0 ;
}
output:
Entrer le nombre des ateliers : 5
Enter String : a
s
d
f
g
----->newline to stop the loop
asdfg
Process returned 0 (0x0) execution time : 8.205 s
Press any key to continue.
I entered it as a string not character by character, its not practical to ask the user the enter letter by letter
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
char * inputword(char **);
int main()
{
char *word;
printf("Enter Word:");
word=inputword(NULL);
printf("Word Entered:%s",word);
free(word);
printf("\nEnter Word 2:");
inputword(&word);
printf("Word Entered:%s",word);
free(word);
return 0 ;
}
char *inputword(char **word)
{
char *str=NULL,ch,*memerr="Memory Error";
int i=0,flag=1;
do
{
str=realloc(str,((i+1)*sizeof(char)));
if(!str)
{
printf(memerr);
exit(1);
}
ch = getch();
switch(ch)
{
case 13:
str[i] = '\0';
putc('\n',stdout);
flag=0;
break;
case '\b':
if(i>0) i--;
str[i--]='\0';
printf("\b \b");
break;
default:
str[i] = ch;
putc(ch,stdout);
}
i++;
}while(flag);
if(word!=NULL)
*word=str;
return str;
}
output:
Enter Word:Hai, How are You?(1 String)
Word Entered:Hai, How are You?(1 String)
Enter Word 2:Hai, How are You?(2 string)
Word Entered:Hai, How are You?(2 string)
Process returned 0 (0x0) execution time : 58.883 s
Press any key to continue.
This question already has an answer here:
How to use sscanf in loops?
(1 answer)
Closed 4 years ago.
I used sscanf to segment one string taken from the input and store every token in a structure. The problem is that sscanf only reads the first word of the string and doesn't move ahead to the next word, printing the same token over and over. Here's the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define dim 30
typedef struct string {
char* token[dim];
}string;
int main() {
string* New = (string *)malloc(dim*sizeof(string));
char* s;
char buffer[dim];
int i = 0, r = 0, j = 0;
s = (char*)malloc(sizeof(char*));
printf("\nString to read:\n");
fgets(s, dim, stdin);
printf("\nThe string is: %s", s);
while(sscanf(s, " %s ", buffer) != EOF) {
New->token[i] = malloc(dim*sizeof(char));
strcpy(New->token[i], buffer);
printf("\nAdded: %s", New->token[i]);
++i;
}
}
For example, if i give "this is a string" as an input, sscanf will only get the word "this" multiple times without moving on to the next word.
You need to increment the pointer of the source sscanf() reads from, so that it won't read from the same point, again and again.
Furthermore, the memory dynamically allocated for s by you didn't make any sense. It was too less in any case. By the call to fgets() later in the code I can see you meant to say s = malloc(dim * sizeof(char));, so I went ahead and fixed that.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define dim 30
typedef struct string {
char* token[dim];
} string;
int main() {
string* New = malloc(dim*sizeof(string));
char* s;
char buffer[dim];
int i = 0;
s = malloc(dim * sizeof(char));
fgets(s, dim, stdin);
printf("The string is: %s\n", s);
char* ptr = s;
int offset;
while (sscanf(ptr, "%s%n", buffer, &offset) == 1) {
ptr += offset;
New->token[i] = malloc(strlen(buffer) + 1);
strcpy(New->token[i], buffer);
printf("Added: %s\n", New->token[i]);
++i;
}
// do work
for(int j = 0; j < i; ++j)
free(New->token[i]);
free(New);
free(s);
return 0;
}
Output:
The string is: this is a string
Added: this
Added: is
Added: a
Added: string
PS: I am not sure about the schema of structures you have in mind, maybe you need to spend a moment or two, thinking about that twice; I mean whether your design approach is meaningful or not.
PPS: Unrelated to your problem: Do I cast the result of malloc? No!
Edit: As #chux said, " " in " %s%n" of sscanf() serves no purpose. I changed it to "%s%n".
Moreover, in order to reserve exactly as much memory as needed (which is the thing to do, when dealing with dynamic memory allocation), New->token[i] = malloc(dim*sizeof(char)); was changed to New->token[i] = malloc(strlen(buffer) + 1);.
I am trying to create a small c program that will read a string with arbitrary size, without having any memory leaks.
According to my research, the function malloc can be used to allocate a number of bytes for whatever data we want to store.
In my program, I start by allocating space for 0 characters, and I make the pointer word point to it. Then whenever I read a single character, I make a pointer oldWord that points to word, which frees the old memory location once I allocate a larger memory location for the new character.
My research shows that the function free can be used to free an old memory location that is no longer needed. However, I am not sure where I am going wrong. Below you can see my code.
#include <stdio.h>
#include <stdlib.h>
int main(void){
char *word = malloc(0);
printf("Enter name: ");
readWord(word);
printf("Your name is: %s\n", word);
free(word);
word = realloc(0);
printf("Enter name: ");
readWord(word);
printf("Your name is: %s\n", word);
free(word);
return 0;
}
void readWord(char *word){
int i = 0;
char *oldWord, c = getchar();
while(c != ' ' && c != '\n'){
oldWord = word;
word = realloc(word, i + 1);
free(oldWord);
word[i++] = c;
c = getchar();
}
oldWord = word;
word = realloc(word, i + 1);
free(oldWord);
word[i] = '\0';
}
The problem as I see it here is with
free(oldWord);
without checking the failure of realloc(). In case realloc() is success, passing the same pointer to free() causes undefined behavior.
That said, some more notes
a syntax like
word = realloc(word, i + 1);
is dangerous, in case realloc() fails, you'll lose the actual pointer, too. You should use a temporary pointer to hold the return value of realloc(), check for success and only then, assign it back to the original pointer, if you need.
In your code, c is of char type, which may not be sufficient to hold all the possible values returned by getchar(), for example, EOF. You should use an int type, that is what getchar() returns.
There are multiple problems in your code:
you free the pointer you passed to realloc(). This is incorrect as realloc() will have freed the memory already if the block was moved.
Otherwise the pointer is freed twice.
The pointer reallocated bu readWord() is never passed back to the caller.
Allocating a 0 sized block has unspecified behavior: it may return NULL or a valid pointer that should not be dereferenced but can be passed to free() or realloc().
You do not test for end of file: there is an infinite loop if the file does not have a space nor a linefeed in it, for example if the file is empty.
you do not have a prototype for readWord() before it is called.
Here is an improved yet simplistic version:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
char *readWord(void);
int main(void) {
char *word;
printf("Enter name: ");
word = readWord();
if (word == NULL) {
printf("Unexpected end of file\n");
else
printf("Your name is: %s\n", word);
free(word);
return 0;
}
char *readWord(void) {
int c;
size_t i = 0;
char *word = NULL;
while ((c = getchar()) != EOF && !isspace(c)) {
word = realloc(word, i + 2);
if (word == NULL)
break;
word[i++] = c;
word[i] = '\0';
}
return word;
}