Array of pointers to string - c

When we are using a 2-D array of characters we are at liberty to either initialize the strings where we are declaring the array,or receive the string using scanf() fucntion.However when we are using an array of pointers we can not receive the strings from keyboard using scanf(). why?
#include<stdio.h>
int main()
{
char *names[6];
int i;
for(i=0;i<=5;i++)
{
printf("Enter name:");
scanf("%s",names[i]);
}
return 0;

Your code doesn't work because it invokes undefined behavior by storing strings into pointers which are not initialized to point to anything. You need to use malloc().
valgrind is a tool which would catch this sort of program for you, automatically.

char *names[6];
declares names as an array of pointers to char but does not allocate memory for elements of names. You need to allocate memory for each element before writing to it, otherwise it will invoke undefined behavior.
Try this:
for(i = 0; i <= 5; i++)
{
printf("Enter name:");
names[i] = malloc(SIZE); // SIZE is for length of string
if( names[i] != NULL)
scanf("%s", names[i]);
}

scanf does not allocate memory automatically, so you have to allocate a buffer for storing the input before calling scanf.
#include<stdio.h>
int main()
{
char *names[6];
int i;
for(i=0;i<=5;i++)
{
printf("Enter name:");
names[i]=(char *)malloc(256); // 256 is size of buffer
scanf("%s",names[i]);
}
return 0;

Related

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;
}

Dynamically inputting values in a structure and printing these values

I wrote this code for a structure stud, that will input the number of students whose record is to be stored, and then print the same. I'm not sure where exactly I'm going wrong.
#include<stdio.h>
struct stud{
int id;
char name[50];
float points;
}s[1000];
int main(){
int i,n;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&s[i].id);
scanf("%c",s[i].name);
scanf("%f",&s[i].points);
}
for(i=0;i<n;i++){
printf("ID: %d\n",s[i].id);
printf("First Name: %c\n",s[i].name);
printf("Points: %f\n",s[i].points);
}
return 0;
}
Change
scanf("%c",s[i].name);
to at least
scanf("%49s",s[i].name);
and the same for printf() call also. %c is for a single char, for a string, you'd need %s. Also, don't forget to check the return value of scanf() for success.
That being said, better to use fgets() for user input. Something like
if( fgets (s[i].name, sizeof(s[i].name), stdin) != NULL ) { /*......*/ }

Coding a string length function using pointer arithmetic

I'm in a beginner CS class learning C and we were tasked with coding a function to find string length using only string pointers. I have the following code:
#include <stdio.h>
int strlength(char* str);
int main() {
char *str;
int comp;
printf("Please enter the string: ");
scanf("%s", str);
printf("The length of the string is: %d\n", strlength(str));
return 0;
}
int strlength(char *str) {
int length = 0;
while(*str != '\0') {
length++;
str++;
}
return length;
}
I'm not really sure where I'm getting a segmentation fault. I've tried making a second pointer in the strlength function that equals str and incrementing that, but that also gives me a segmentation fault. Any insight would be appreciated!
char *str;
int comp;
printf("Please enter the string: ");
scanf("%s", str);
You should allocate memory in heap ( with malloc ) for *str before scanf. If you dont want to use malloc change it to char[number] so it can allocate memory in stack instead of heap

Passing pointers to string arrays to toupper() in C

I'm trying to pass a pointer array of strings to function toupper() in C.
main() {
char *choice[1];
scanf("%s", choice);
printf("%s", toupper(&choice[0]));
}
I always type in a lowercase word such as "modify" to test it. Different variations of this, such as toupper(*choice[0]) or toupper(*choice) or mixtures of them all, including &, have either thrown an error or returned the same lowercase "modify". Any suggestions?
To start with array of char pointers having one element doesn't make much sense to me since it will only point to one string.Why not declare a char array if you just want a single string?
Prototype of toupper is this:
int toupper( int ch );
It doesn't take an array.
You can try like this :
#include <stdio.h>
#include <ctype.h>
int main()
{
char str[25];
int i = 0;
setbuf(stdout,NULL);
printf ("enter the name \n");
fgets (str,sizeof str-1, stdin);
printf ("the name entered in upper case is :\n");
while (str[i])
{
int c = str[i];
printf ("%c",toupper(c));
i++;
}
return 0;
}
NOTE- Do not use scanf for taking strings try fgets , its better.
Before you call scanf, you need to allocate some space for the characters to be stored in. You only allocate a single pointer and then you don't even set it to point to anything. Similarly, toupper returns the converted character, which is not a string, so passing it to printf through %s is also wrong.
Something like this should serve the purpose.
#include<stdio.h>
#include<ctype.h>
void StrToUpper(char *str)
{
while(*str != '\0')
{
*str = toupper(*str);
str++;
}
}
int main()
{
char *choice[1];
choice[1] = new char[10];
scanf("%s", choice[1]);
StrToUpper(choice[1]);
printf("%s", choice[1]);
return 0;
}
In the program, you have array of pointers.
So:
Allocate memory for your string
call toupper(choice[0][0]);
toupper takes only a character value (between 0 and 255), not a pointer or array.

segmentation-error in ubuntu gcc

#include<stdio.h>
int main()
{
char *ch;
int n=10;
gets(ch);
puts(ch);
printf("%d\n",n);
}
#include<stdio.h>
int main()
{
char *ch;
int n=10;
gets(ch);
printf("%d\n",n);
puts(ch);
}
In the first one , the segmentation error occurs at print(n) and in second one it occurs at puts(ch).No error occurs if print(n) is also used just after declaring n.
gets() is dereferencing an unitialized pointer, causing undefined behaviour.
Allocate memory for ch and don't use gets() as there is no way to limit the number of characters read, meaning potentially writing beyond the bounds of the destination array.
Example using fgets():
char ch[128];
if (fgets(ch, 128, stdin))
{
}
Use fgets and allocate memory for your "buffer" (via malloc) to hold the given string. At the end call free for your pointer.
#include<stdio.h>
#include<stdlib.h>
int main(){
char * ch = (char*) malloc(sizeof(char)*10);
//or by using this: char ch[10];
int n=10;
gets(ch);
puts(ch);
printf("%d\n", n);
free(ch);
}

Resources