Incorrect String Length Using Pointer - c

I'm trying to create a program that displays the string length of an entered string with a pointer to aforementioned string. When I input a string without spaces, the length is correct. When I enter a string with spaces, the length is incorrect. Please describe my mistake and recommend ways to fix it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int l,n;
char s[n], *p=s;
*p = malloc(sizeof(char)*5);
n = sizeof(*p);
if (p==NULL)
printf("Unable to allocate memory");
printf("Input a string: ");
scanf("%s", p);
l = strlen(p);
printf("\nLength of given string: %d\n", l);
}
Input:
Input a string: June 27
Output:
Length of given string: 4

Aside from the obvious memory allocation shortcomings mentioned in the comments, "%s" used with scanf will read up to the first whitespace. If you want to read complete lines (up to newline), consider using fgets instead.

The program has the following defects:
The variable n is uninitialized before its usage in char s[n].
You're trying to read the whole line by scanf() which only reads to the next whitespace.
Allocated memory of 5 length, which is an overflow and tends to Undefined Behavior.
The (char *) is not explicitly defined during memory allocation.
Code redefined:
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
int main(void) {
char *s;
s = (char *)malloc(sizeof(char) * MAX); // allocating memory correctly
if (s == NULL) {
printf("Memory allocation failed.\n");
return -1;
}
printf("Enter a string: ");
fgets(s, MAX, stdin); // reading the entire line
size_t len = 0;
while (s[len++]); // alternative of strlen()
printf("String length is: %d\n", len);
return 0;
}
A sample output:
$ gcc -o prog prog.c; ./prog
Enter a string: Hello world, how are you today?
String length is: 33

Related

can not get dynamic string allocation to work

hey guys i have looked around for a solution and tried everything i can think of im new to pointers and dynamic strings and i could really do with some help with problem. im currently learning c and i need to get the user to input a dynamic size for the string length . i need to make it so the users input can not be bigger then 100 . here's where i am at currently . i have the code booting but if i try set the size to let's say 5 i can still input way more chars into the string. cheers really appreciate any help .
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
int maxSize = 100;
char *name = (char*) malloc (maxSize * sizeof (char));
int n;
char text1[]= ("input string size\n");
printf ("your string lenght is %d\n", strlen(name));
//getting size
n=intPrintScanner(text1);
printf ("your size is %d\n",n);
name = realloc (name, sizeof (char) * n);
//printing results
printf ("your string lenght is %d\n",strlen (name));
scanf("%s", name);
printf("your string is %s",name);
free(name);
fflush(stdin);
printf("press any key to close");
getchar();
return (0);
}
Bugs:
You never assign any data to name so it just contains garbage. You can't use strlen on it before you have stored valid data there either. You can store a string inside name by for example using strcpy.
When using realloc, there's no guarantee that the old pointer is the same as the returned pointer. Also, you need error handling. Implement it like this instead:
char* tmp = realloc (name, n);
if(tmp == NULL)
{
/* actual error handling here in case realloc fails */ }
}
name = tmp; // assign pointer to the new area only if allocation succeeded
fflush(stdin); is not well-defined, never use fflush on input streams. Instead you should discard unwanted line feed characters from stdin - which could be as trivial as an extra getchar() call just after reading something. Check out How to read / parse input in C? The FAQ for lots of general good advise regarding how to take input from stdin.
Cosmetic/style:
No need for parenthesis here: char text1[]= ("input string size\n");. All it achieves it to make the code look strange.
The correct form of main is int main (void). The int main() is obsolete style.
There is no need to wrap the expression passed to return in a parenthesis.
There is never a need to multiply something with sizeof (char), since sizeof (char) is by definition always 1 no matter system.
There is no need to cast the result of malloc.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
char* read_until(int fd, char end) {
int i = 0, size;
char c = '\0';
char* string = (char*)malloc(sizeof(char));
while (1) {
size = read(fd, &c, sizeof(char));
if (c != end && size > 0) {
string = (char*)realloc(string, sizeof(char) * (i + 2));
string[i++] = c;
} else {
break;
}
}
string[i] = '\0';
return string;
}
int main()
{
char *name;
int correct=0;
do{
write(1,"Put a name: ",strlen("Put a name: "));
name = read_until(STDIN_FILENO,'\n');
if(strlen(name) > 99){
write(1,"Error\n",strlen("Error\n"));
}else{
correct=1;
}
}while(correct != 1);
write(1,name,strlen(name));
free(name);
}
Try using write and read instead of printf and scanf, it is better for allocating dynamic memory, read and try to understand the read_until function, there are better ways to do main.

Dynamic memory allocation of string and placement of this string in a char array

I want to have an array of strings and the user to enter a string at a time. The program should either end if the the array is full or when the user skips an input (so the string would be equal to "\n".
Problem is that I have to dynamically allocate memory for each of these strings and I cant find a way to do that efficiently.
Excuse my English on this one but the array should be an array of pointers to char (for example char *pin[MAX])
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 5
int main()
{
char *pin[MAX];
char s[] = "";
int n = 0;
while(s != "\n"){
printf("Enter a string: ");
gets(s);
pin[n] = malloc(sizeof(char)*strlen(s));
strcpy(pin[n], s);
n++;
if(n = MAX - 1) break;
}
for(int i = 0; i < MAX; i++){
printf("%s ", *pin[i]);
}
return 0;
}
Take input with fgets and store it in a temporary buffer (128 or 256 bytes large etc).
Call strlen on the read string stored in this buffer to see how much to allocate.
Allocate memory with malloc for pointer pin[n] and strcpy the string there.
NOTE:
char *s; ... while(s != is nonsense since s has not been initialized.
s != "\n" is nonsense since that's not how you compare strings in C.
pin[n] == &s; is nonsense because it's just random stuff typed out without the programmer knowing why. Programming by trial & error doesn't work.
In general you need to study arrays and pointers before strings.

C program segfaulting with strtok

#include <stdio.h>
#include <unistd.h>
int main(void)
{
int n_of_words = 0;
#define MAX_STR_SZ 256
// asking for user input
char string[50];
printf("\nPlease input a string of text.\n\n");
fgets(string, MAX_STR_SZ, stdin);
char * words[n_of_words];
// extracting the first word
words[n_of_words] = strtok(string, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
// looping through the string to extract all other words
while( words[n_of_words] != NULL )
{
n_of_words ++;
words[n_of_words] = strtok(NULL, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
}
sleep(10);
return 0;
}
I'm very new to programming, but I was trying to write a function to extract words from a user inputted string and save them in an array for later use in the program. I added the 2 printf lines of code to see if it was working properly.
I always get a segmentation fault error after the second iteration of the while loop.
Also, somehow this problem didn't present itself when I compiled the same code on the CS50 ide (Cloud9), but it happens in any other case.
Few issues which can be resolved to prevent segmenatation fault:
No string.h header in the source code for strtokfunction
#include <stdio.h>
#include <unistd.h>
Macros are generally declared in the top of the source code and not inside any function
#define MAX_STR_SZ 256
The char string array is of length 50 but the fgets is allowing 256 and can lead to bufferoverflow.
char string[50];
printf("\nPlease input a string of text.\n\n");
fgets(string, MAX_STR_SZ, stdin);
The value of the variable n_of_words is 0. So, the declaration
char * words[n_of_words];
Will not create an array of the desired length.
The root cause of your question lies here:
while( words[n_of_words] != NULL )
{
n_of_words ++;
words[n_of_words] = strtok(NULL, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
}
You are accessing a memory location which was never declared,
n_of_words ++;
words[n_of_words] = strtok(NULL, " "); //words[1] or any index was never declared.
Every C program gets for free a list of the command line parameters, in general declared as int main(int argc, char* argv[]); or int main(int argc, char** argv);
This is precisely what you are trying to replicate with int n_of_words and char* words[n_of_words];
But you are doing it the wrong way.
A first note on this 3 lines from your code:
#define MAX_STR_SZ 256
char string[50];
fgets(string, MAX_STR_SZ, stdin);
You are setting 256 as the limit for fgets() to read, but you have only 50 chars in string. Many times it will work in this case, since you are reading from the keyboard and many of us would not key more than a few words in, but you have a problem. Change the limits.
strtok() is probably not the best one to choose here. A single loop using scanf() could read many lines and break all of then in words skipping over the newlines and such, and you may find it easier to code.
Anyway, back to your code: since you do not know in advance the number of words, you can estimate a limit or allocate memory for the strings one by one, or even in blocks. But
you need to allocate memory for the strings you will have a SegFault
at the moment you try to write in the words[] array.
I changed a minimum of your code so you can see an example, and I fixed the number of strings in a #define similar of what you have written so far.
A simple way to go is declare --- as C does in main() --- words[] as char** and allocate memory for them as soon as you know you have at least one string to record.
But then you need to note that you will have just the pointers. They are still pointing to nothing.
As soon as you have a string to load you need to allocate memory for it, plus 1 byte for the terminating '\0', and then copying the string and saving the address in the corresponding pointer in the words[] array.
See the code.
#define MAX_STR_SZ 256
#define MAX_N_OF_STRINGS 30
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// https://stackoverflow.com/questions/63343800/
// c-program-segfaulting-with-strtok
int main(int argc, char** argv)
{
int n_of_words = 0;
int max_n_of_words = MAX_N_OF_STRINGS;
char** words;
// asking for user input
char string[MAX_STR_SZ];
printf("\nPlease input a string of text: ");
fgets(string, MAX_STR_SZ, stdin);
string[strlen(string) - 1] = 0; // drops the final '\n'
printf("full string was '%s'\n", string);
if (strlen(string) == 0) return -1; // no input
// we have at least one byte
// before anything build words[]
words = (char**)malloc(max_n_of_words * sizeof(char*));
// now words[] points to an array of pointers to char
// extracting the first word
char* a_word = strtok(string, " ");
// looping through the string to extract all other words
do
{
printf("\n%i %s\n", 1+n_of_words, a_word);
words[n_of_words] = malloc(1 + sizeof(a_word));
strcpy(words[n_of_words], a_word);
n_of_words++;
if (n_of_words >= MAX_N_OF_STRINGS) break;
a_word = strtok(NULL, " ");
} while (a_word != NULL);
printf("\n%d words at the end of the loop:\n\n", n_of_words);
for (int i = 0; i < n_of_words; i += 1)
{
printf("%i %s\n", 1 + n_of_words, words[i]);
free(words[i]); // deletes words[i]
}; // for()
free(words); // deletes the array
return 0;
};
As a result:
Please input a string of text: we have at least one byte
full string was 'we have at least one byte'
1 we
2 have
3 at
4 least
5 one
6 byte
6 words at the end of the loop:
1 we
2 have
3 at
4 least
5 one
6 byte
There are a few problems that could lead to a seg fault. First, I get warnings compiling your code:
../main.c: In function 'main':
../main.c:17:25: warning: implicit declaration of function 'strtok' [-Wimplicit-function-declaration]
words[n_of_words] = strtok(string, " ");
^~~~~~
../main.c:17:23: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
words[n_of_words] = strtok(string, " ");
^
../main.c:24:27: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
words[n_of_words] = strtok(NULL, " ");
All of this is because you didn't include the proper header for strtok, namely string.h. This could potentially cause problems because the default return type is assumed to be int, which may not be large enough to hold a pointer.
Second, you are passing an incorrect size to fgets(). The size should be the size of the buffer for holding the result. If the buffer is overflowed, undefined behavior results.
Finally, the words array is declared with a size n_of_words, which is zero at that point. This results in a zero size array. Arrays in C do not automatically grow.
Here is your code with these issues fixed:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
int n_of_words = 0;
#define MAX_STR_SZ 256
// asking for user input
char string[MAX_STR_SZ]; // <--- Use macro to define buffer size
printf("\nPlease input a string of text.\n\n");
fgets(string, sizeof string, stdin);
char * words[MAX_STR_SZ]; // <--- Should never be more words than characters in the buffer
// extracting the first word
words[n_of_words] = strtok(string, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
// looping through the string to extract all other words
while( words[n_of_words] != NULL )
{
n_of_words ++;
words[n_of_words] = strtok(NULL, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
}
sleep(10);
return 0;
}

C reading lines from stdin

My goal is to read every line from a piped .txt file with the getline() function, but I somehow get a error every time I use this function:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
int Chars;
int size = 10;
char *string;
printf("Please enter a string: ");
string = (char*) malloc(size);
Chars = getline(&string, &size, stdin);
if (Chars == -1)
{
puts("ERROR!");
}
else
{
puts("You entered the following string: ");
puts(string);
printf("\nCurrent size for string block: %d", Chars);
}
return 0;
}
I always get the errorcode: [Error] Id retruned 1 exit status
I've reproduced the linking error on DevC++, in which getline() seems to be missing even after forcing recent C revisions with gcc compiler options such as -std=c11.
So I've rewritten your code using fgets():
char *fgets(char *s, int size, FILE *stream);
It is for sure more portable than getline but has a few differences:
It reads up to size-1 characters if the newline is not encountered before this limit (it automatically appends the string terminator). So it doesn't manage buffer reallocation
The resulting string contains the '\n' character, if found
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STR_SIZE 32
int main( void )
{
int len = 0;
char *str;
printf("Please enter a string: ");
str = malloc(MAX_STR_SIZE); /* (1) */
while( 1 )
{
size_t newline_pos;
fgets( str, MAX_STR_SIZE, stdin );
/* (2) */
if( len == 0) /* (3) */
{
puts("You entered the following string: ");
}
newline_pos = strcspn(str, "\n" );
str[newline_pos] = '\0';
len += strlen(str); /* (4) */
fputs(str, stdout);
if(newline_pos < MAX_STR_SIZE-1) /* (5) */
break;
}
printf("\n\nCurrent size for string block: %d", len);
free( str ); /* (6) */
return 0;
}
So, basically, I just use fgets to read from stdin, iterating until the '\n' character is found. In order to understand is this condition is met, I use strcspn() function, and I use the same function to remove the newline from the resulting string.
A few notes/assumptions (check the corresponding number in code section):
Casting the result of malloc is required only if you are compiling with a C++ compiler. It can be omitted in C
Removed fgets error check: it returns NULL in case of error (no chars read before EOF is found. It won't happen reading from stdin)
Checking for len==0 we make sure that the "You entered the following string: " is printed only once
The length of the string is calculated by summing the length of the strings read in every iteration
The break condition is met when the string contains '\n'. Otherwise strcspn's return value will be MAX_STR_SIZE
Even if the OS will release all the dynamic memory used by the program, on return, it is a good habit always freeing it anyway

Which is the best way in this case to extract the substring from a string which is inputted by the user in C

Let's say I have the following string stored in char *m;
char *m = "K: someword\r\n";
The m will be inputed by the user so the user will write in the console:
K: someword\r\n
The someword can have different length, while K: \r\n will always be the same.
Now my question is, which is the best way after I read this input to extract someword from it and save it into a new char* variable?
Use sscanf() like this:
#include <stdio.h>
int main (void)
{
char buffer [50], k, return_car, new_line;
int n = sscanf ("K: someword\r\n", "%c: %s%c%c", &k, buffer, &return_car, &new_line);
printf ("The word is \"%s\". sscanf() read %d items.\n", buffer, n);
return 0;
}
Output:
The word is "someword". sscanf() read 4 items
Since both the substrings we aren't interested in ("K: " and "\r\n") are of fixed length, you can do this:
char *s;
size_t len = strlen(m);
s = malloc(len);
strcpy(s, m + 3);
s[len - 4] = 0;
printf("%s\n", s);
free(s);
Note that I declared a new char * variable to copy to since m is in read-only memory, and that robust code would handle the case where malloc failed and returned NULL.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *m = "K: someword\r\n";
const size_t someword_len = strlen(&m[3]);
char *someword = malloc(someword_len);
if (someword == NULL) { fprintf(stderr, "Malloc error\n"); abort(); }
memcpy(someword, &m[3], someword_len - 2);
someword[someword_len - 1] = '\0';
puts(someword);
free(someword);
}
You assume that string m always starts with "K: " (that's 3 characters) and ends with "\r\n" (that's two characters).
I believe strlen(m) will be faster then strchr(m, '\r') or strrchr(m, '\r') on most platforms
After you have the length of the string, using memcpy instead of strcpy will be faster.
Remember to null terminate your string
Remember to handle errors.

Resources