Code for extracting string crashes - c

I wrote this code to accept a string and until where it should extract a string and print it.
Given below is the code:
#include <stdio.h>
#include <stdlib.h>
int strlen(char s[]){
int i = 0;
while(s[i]!='\0')
i++;
return i;
}
char *extract(char s[], int n){
char *result = (char *)malloc(sizeof(char)*3);
for(int j=0;j<n;j++){
result[j]=s[j];
}
return result;
}
int main(){
char str[100];
int till;
printf("Enter a string: ");
scanf("%s", str);
printf("Until where to extract: ");
scanf("%d", till);
char *ret = extract(str, till);
printf("%s is extracted", ret);
return 0;
}
This is what happens:
Enter a string: hello
Enter from where to extract: 2
And then it crashes.
I don't see what the problem is.

At very first, you need to change
scanf("%d", till);
to
scanf("%d", &till);
as scanf() needs a pointer to the data type argument for the supplied format specifier. Using a wrong type of argument causes undefined behavior.
Then, there are many issues, like
You're allocating only 3 chars, where you're looping based on the incoming value of n.
You never checked for the success of malloc().
You're not null-terminating your result which you intend to use as a string later.
That said,
You should always limit the input for your strings to avoid the possibility of overrun, like
scanf("%99s", str); //considering the length of the array is 100.
There is a library function strlen() available with string.h. Even if you want to roll out your own functions, try to follow a different naming convention.
You did not free() the allocated memory.

I you add -Wall to command when you compile your code you'll see
test.c:40:2: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Wformat=]
scanf("%d", till);
^
Then change you must change it to scanf("%d", &till);

In addition to the other suggestions:
char *result = (char *)malloc(sizeof(char)*3);
Should be:
char *result = malloc(n + 1);

Related

Creating a function to ask question from the user using scanf in C

I'm very new to C but am trying to make a function to ask the user a question using scanf, any suggestions of how I should go about this, this is currently what I have.
#include <stdio.h>
char name[100];
int num, days;
int askQ(char *question, char *x, char *answer) {
printf("%s", question);
fflush(stdout);
scanf(x,&answer);
return 1;
}
int main() {
askQ("hello? | ", "%s\n", &name);
printf("%s", name);
return 0;
}
A couple of things make this a bit tricky. Your requirement for an arbitrary format string makes it difficult to know how arguments are to be passed to scanf(). E.g. an int argument will require that you pass the address of the receiving variable to scanf(), whereas a string does not require the address because the "string" is already a pointer.
Similarly you should check the return value from scanf() to ensure that the input was processed as expected - that's hard for an arbitrary format string.
Perhaps, if you really need arbitrary input parsing you can use vscanf(), but at your level I would not recommend that.
If you choose to keep it simple so that you simply have a prompt with a single string response then you might do this:
#include <stdio.h>
int askQ(char *question, char *format, char *answer) {
printf("%s", question);
int i = scanf(format, answer);
return i == 1;
}
int main() {
char name[100]; // accept up to 100 chars input
if (askQ("hello? | ", "%s", name))
printf("Response: %s\n", name);
else
printf("Failed to get valid response from user\n");
}

How to fix format error for char* and char**

i'm writing a kind of phonebook program and i'm using typedef struct to store the name and number of the people. The user will input name and number as a string format, but when i try to scan it, the compiler gives me an error saying "format specifies type char * but the argument has type char **. Any solution on this? i really don't understand what it means. Error is on first loop on both scans any help would be appreciated. Thanks!
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *name;
char *number;
}
person;
int main(void)
{
int n;
scanf("%i", &n);
person people[n];
for(int i = 0; i < n; i++)
{
scanf("%s", &people[i].name); // these 2 lines are buggy
scanf("%s", &people[i].number);
}
char *findName;
scanf("%s", &findName);
for(int i = 0; i < n; i++)
{
if(strcmp(people[i].name, findName) == 0)
{
printf("%s\n", people[i].number);
}
else
{
return 1;
}
}
return 0;
}
The statement
scanf("%s", &people[i].name);
is wrong for two reasons:
First of all the %s format expects a char * argument. By using the address-of operator you get a value of type char **. Mismatching format specifier and argument type leads to undefined behavior.
If you remove the address-of operator you will pass an uninitialized pointer, it's not pointing anywhere valid. This means scanf will write the string to some seemingly random location in memory. Again this leads to undefined behavior.
A simple way to solve the second issue, you could change the structure to contain arrays of characters instead, as in:
typedef struct
{
char name[64];
char number[64];
}
person;
Then use a limit in the format so the scanf function will not attempt to read a string longer than the arrays:
scanf("%63s", people[i].name); // The array decays to a pointer to its first element
Note that the length in the format is 63, so the string null-terminator will fit in the array.
Never use the "%s" format with scanf(). You cannot use it safely.
The problem is, that the user controls how many characters will get written into the memory buffer, but the program needs to supply the memory buffer without knowing how many characters the user is actually going to input. The result is invariable buffer overrun vulnerabilities of your program. Don't do this.
Instead, use allocating input functions. For scanf(), you need to add the "m" modifier:
scanf("%ms", &people[i].name);
This changes the expected argument type from char* to char**, it will malloc() a sufficiently sized buffer for you, and store the address at the given location. I.e, this call does precisely what you want it to do. Just don't forget to free() the resulting string once you are done with it.
The "m" modifier works with the "%ms", "%m[" and "%mc" conversion specifiers, i.e. all the conversions that can output a string of unknown length.
(The other allocating input functions that you should keep in mind are getline() and getdelim().)
findname is already a char *.
You ask for reference of this value, it represent char **
scanf("%s", &findName);
Try this :
scanf("%s", findName);
Here is an example with dynamically allocated memory and scanf with %ms:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct
{
char *name;
char *number;
}
person;
int main(void)
{
int n = 0;
char *findName ;
scanf("%i", &n);
if (n == 0) return 1;
person* people = (person*)malloc(n * sizeof(person));
if (people == NULL) return 1;
for(int i = 0; i < n; i++)
{
person p = people[i];
printf("Enter Name and number:\n");
printf("Number: ");
scanf("%ms", &(p.number));
printf("Name: ");
scanf("%ms", &(p.name));
people[i] = p;
}
printf("Enter name to search: ");
scanf("%ms", &findName);
printf("Searching for: %s\n", findName);
for(int i = 0; i < n; i++)
{
person p = people[i];
if(strcmp(p.name, findName) == 0)
{
printf("Number for %s is %s\n", p.name, p.number);
}
}
free(findName);
for(int i = 0; i < n; i++)
{
//notice how we have to free the strings for each name and number,
// and not just the people array
free(people[i].name);
free(people[i].number);
}
free(people);
return 0;
}

Error on the format

11: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[100]’
This is my error....Cant fix it...
#include <stdio.h>
#include <string.h>
int main()
{
char *a;
char *count;
char str[100];
int i ;
printf("\n:enter string for Palindrome test\t");
scanf("%s", &str);
i= strlen(str);
//a=(char *)malloc(i*sizeof(char));
a=&str[0];
count=&str[i-1];
while((*(a++)==*(count--)) && i>=1)
{ i--; }
if(i==0) { printf("\n%s is a palin",str);}
else { printf("\n%s is not palin",str);}
}
Sure you can fix it. Just don't pass the wrong type. Change:
scanf("%s", &str);
To:
scanf("%s", str);
Or, equivalently:
scanf("%s", &str[0]);
You don't always use an ampersand passing arguments to scanf(). If the format string contains either a %c or a %s, it will be looking for a char* type. When you call it with &str, you are calling it with a char** type, or as the compiler says, a char*[100] (a pointer to an array of 100 chars).

compare 2 inputs from keyboard with strcmp leads to segmentation fault

I am new student in c language and I just come up with this. I code:
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[80];
printf("Enter sth: ");
char st1 = gets(str);
printf("Enter sth: ");
char st2 = gets(str);
if(strcpy(st1,st2))
printf("Same\n");
else
printf("Different\n");
return 0;
}
My goal is to check if the 2 strings i enter from the keyboard are the same. I compile it and i get some warnings:
hello.c: In function ‘main’:
hello.c:9:16: warning: initialization makes integer from pointer without a cast [enabled by default]
hello.c:12:16: warning: initialization makes integer from pointer without a cast [enabled by default]
hello.c:14:5: warning: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast [enabled by default]
/usr/include/string.h:128:14: note: expected ‘char * restrict’ but argument is of type ‘char’
hello.c:14:5: warning: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast [enabled by default]
/usr/include/string.h:128:14: note: expected ‘const char * restrict’ but argument is of type ‘char’
Enter sth: asd Enter sth: asd Output: Segmentation fault (core dumped) Segmentation Fault i saw that is an error when you want to access sth that it doesnt exist!
I search it a little here in Stackoverflow with similar questions and here but i dont understand why this code isnt working. Thank you!
You are treating an address of char variable as string and using strcpy instead of strcmp. This:
char st1 = gets(str);
char st2 = gets(str);
if(strcpy(st1,st2))
was meant to be:
char st1[255], st2[255];
scanf("%254s", st1);
scanf("%254s", st2);
if(strcmp(st1, st2) == 0)
if(strcpy(st1,st2))
^
|
strcmp
strcpy is for string copy, not for string compare.
To remove segmentation fault change char str1 to char *str and char str2 to char *str2.
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[80];
char str2[80];
printf("Enter sth: ");
char *st1 = gets(str1);
printf("Enter sth: ");
char *st2 = gets(str2);
if(!strcmp(st1,st2))
printf("Same\n");
else
printf("Different\n");
return 0;
}
You get the compile warnings because gets() returns char *, but you declare str1 and str2 as char.
You get the segmentation fault because it should be:
if(strcpy(st1,st2))
should be used with strcmp, I guess it's a typo because strcmp is in your question's tag :)
Note: Never use gets(), you can use fgets() instead.
char *st1 = fgets(str, 80, stdin);
you are trying to use strcmp but you using strcpy.
This code may help you.
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[80];
char str2[80];
printf("Enter sth: ");
gets(str1);
printf("Enter sth: ");
gets(str2);
if(!strcmp(str1,str2))
printf("Same\n");
else
printf("Different\n");
return 0;
}
Here is how to fix your code :
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[80];
char str2[80];
printf("Enter sth: ");
//notice that gets is not safe,
//if the line is too long (>79 char), you'll have a buffer overflow
gets(str);
printf("Enter sth: ");
gets(str2);
//strcmp instead of strcpy
if(strcmp(str,str2) == 0)
printf("Same\n");
else
printf("Different\n");
return 0;
}

stack with finding character inside string in C language

#include <stdio.h>
#include <string.h>
main()
{
int i;
int *b, *z;
char name[30];
char vowel[5] = {'A', 'E', 'I', 'O', 'U'};
char consonants[23] = {'B','C','D','F','G','H','J','K','L','M','N','P','Q','R','S','T','V','W','X','Y','Z'};
printf ("input the string: ");
scanf ("%s", name);
printf ("The string is %s\n", name);
for (i=0; name[i]!='\0'; i++){
if
(b=strchr(vowel, name[i]) != NULL) {
printf ("The vowels are: %s\n", b); }
else if
(z=strchr(consonants, name[i]) != NULL) {
printf ("The consonants are: %s\n", z);
}
}
}
I am trying to find how many vowels and consonants in array. That's the only algorithm that our teacher showed us, but it doesn't work. Any one can point me to my mistakes?
I just did one more try, with all your advices,
#include <stdio.h>
#include <string.h>
int main()
{
int vow, cons, i;
char *s, *s1;
char name[30];
char vowel[6] = "AEIOU";
char consonants[21] = "BCDFGHJKLMNPQRSTVWXYZ";
printf ("input the string: ");
scanf ("%s", name);
printf ("The string is %s\n", name);
for (i=0; name[i]!='\0'; i++)
s = strchr(vowel, name[i]);
printf ("The vowels are: %s\n", s);
s1 =strchr(consonants, name[i])) {
printf ("The consonants are: %s\n", s1);
}
return 0;
}
This is how I changed it, with all your advices, what is my other problems? cause still dosen't work fine.
Thanks.
And this is my another version of program
#include <stdio.h>
#include <string.h>
int main()
{
int i;
int counter=0, counter2=0;
char *s;
char name[30];
char vowel[6] = "AEIOU";
char consonants[21] = "BCDFGHJKLMNPQRSTVWXYZ";
printf ("input the string: ");
scanf ("%s", name);
printf ("The string is %s\n", name);
for (i=0; name[i]!='\0'; i++) {
if (s = strchr(vowel, name[i])) {
counter++;
}
else if (s =strchr(consonants, name[i])) {
counter2++;
}
printf ("First counter is %d\n", counter);
printf ("The second counter is %d\n", counter2);
return 0;
}
}
I added counters to count quantity of vowels and consonants, still doesn't work.
strchr() is for searching in strings.
char vowel[] = "AEIOU";
char consonants[] = "BCDFGHJKLMNPQRSTVWXYZ";
#include< stdio.h>
int main()
{
int vowel=0,consonant=0;
printf ("input the string: ");
scanf ("%s", name);
printf ("The string is %s\n", name);
for(int i=0;name[i] !='\0';i++)
{
if( name[i] == 'A' || name[i] == 'E' || name[i] == 'I' || name[i] == 'O' || name[i] == 'U' )
{
vowel++;
}
else
consanant++;
}
printf("%d %d",vowel,consonant);
return 0;
}
When I compile this, I get the following messages:
$ gcc -Wall vc.c
vc.c:4:1: warning: return type defaults to ‘int’ [-Wreturn-type]
vc.c: In function ‘main’:
vc.c:17:8: warning: assignment makes pointer from integer without a cast [enabled by default]
vc.c:17:3: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
vc.c:18:4: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int *’ [-Wformat]
vc.c:20:13: warning: assignment makes pointer from integer without a cast [enabled by default]
vc.c:20:3: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
vc.c:21:4: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int *’ [-Wformat]
vc.c:24:1: warning: control reaches end of non-void function [-Wreturn-type]
So, start by making sure that your return type for main is 'int'
int main(){
and adding a return at the bottom of the function
return 0;
Thereafter, set b and z to be char *s, so that they match the return type of strchr
char *b, *z;
This will get rid of all the warnings.
$ gcc -Wall vc.c
$
Excellent. Now, when we run your program:
$ ./a.out
input the string: aaa
The string is aaa
Segmentation fault
"Segmentation fault" means you're running off the end of an array and reading memory you don't own. Now implement Ignacio Vazquez-Abrams' solution
char vowel[] = "AEIOU";
char consonants[] = "BCDFGHJKLMNPQRSTVWXYZ";
Now your program will run to completion.
$ ./a.out
input the string: AAA
The string is AAA
The vowels are: AEIOU
The vowels are: AEIOU
The vowels are: AEIOU
But it doesn't do much, does it?
So, if you're just trying to count how many vowels and consonants there are, you can just add an integer for each that increments every time the correct type is found and output them at the end:
printf("Vowels:\t%d\nConsonants:\t%d", vowelsFound, consonantsFound);
However, if you're trying to output them as lists, you're going to have much more data manipulation to do. Some links to check out:
Linux Man Page for printf
Linux Man Page for String functions
You have placed the return statement inside the for loop which is preventing it from scanning the entire name array.
When using strchr, you'll also need to convert the current loop character to uppercase for it to match properly since you have defined vowels in uppercase. To use toupper() you need to include ctype.h.
You also don't need to define consonants. What is not a vowel is a consonant.
Here's the code. I've tested it and it works:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
int i;
int counter=0, counter2=0;
char *s;
char name[30];
char vowel[6] = "AEIOU";
printf ("input the string: ");
scanf ("%s", name);
printf ("The string is %s\n", name);
for (i=0; name[i]!='\0'; i++) {
if (strchr(vowel, toupper(name[i])) != NULL) {
counter++;
}
else {
counter2++;
}
}
printf ("First counter is %d\n", counter);
printf ("The second counter is %d\n", counter2);
return 0;
}
Alternatively.
#include <stdio.h>
#include <string.h>
int main() {
int t [256];
int i,c;
int cntw = 0;
int cntc = 0;
const char * vowel="AEIOUaeiou";
const char * consonants="BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz";
memset(t,0,256);
while (*vowel) { t[*vowel] = 1; ++vowel;}
while (*consonants) { t[*consonants] = 2; ++consonants;}
printf ("Input the text: CTRL-D to end\n");
c = getchar();
while(c >=0) {
switch(t[c]) {
case 1: ++cntw; break;
case 2: ++cntc; break;
}
c=getchar();
}
printf ("Text has %d vowel%s and %d consonant%s\n",
cntw,(cntw>1)?"s":"",
cntc,(cntc>1)?"s":"");
return 0;
}

Resources