Creating one array of strings in C fails, why? - c

I tried to create one array of strings in C. Here is the code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main()
{
char *foo[100];
strcpy(foo[0], "Testing this");
printf("%s ", foo[0]);
return 1;
}
But when I compile it, it simply breaks. No error, no nothing, it simply doesn't work and breaks. Any suggestion? When I tri char *foo[10] it works, but I can't work with just 10 strings

You allocated an array of pointers but did not allocate any memory for them to point to. You need to call malloc to allocate memory from the heap.
char *foo[100];
foo[0] = malloc(13);
strcpy(foo[0], "Testing this");
Naturally you would need to free the memory at some later date when you were finished with it.
Your code invokes what is known as undefined behavior. Basically anything can happen, including the code working as you intended. If the version with char *foo[10] works as you intended that's simply down to luck.
As an aside, your main() definition is wrong. It should be int main(void).

You're assigning an unallocated pointer. char *foo[100] is an array of 100 unallocated pointers, and they point to unknown locations in memory, ones which you can probably not access.

You are creating an 100 pointers to point no where. As explained by David, you need to dynamically allocate the memory. However, you can also have the compiler do this for you if you know the size of the strings (or max):
// Create an array of 10 strings of size 100 and initialize them automatically
char foo[10][100] = {0};
// Now you can use it them and not worry about memory leaks
strcpy(foo[0], "text");
// Or use the safer version
strcpy_s(foo[0], 100, "text");

Expanding upon other people's answers:
char *foo;
is a pointer to a character. It may be assigned the address of a single character or assigned the address of the first of a sequence of characters terminated by '\0'. It may also be assigned an address via malloc().
char foo[100];
is space for 100 characters or space for a string of up to 99 characters and a terminating '\0' character.
char *foo[100];
is 100 character pointers, i.e., 100 char *foo; types.

#include <stdlib.h>
#include <stdio.h>
int main(void){
char *foo[100];
foo[0] = malloc(13*(sizeof(char)));
strcpy(foo[0], "Testing this");
printf("%s ", foo[0]);
return 0;
}
This is the corrected version of your code.
MISTAKE: not allocating enough memory for the string.
CORRECTION: using malloc to allocate 13 blocks of memory for the string.

Related

Why do I need "&" in printf when I want to print a pointer

So I wrote this code where I scan 2 strings. One is declared as an array and one as a pointer.
Now to my question: Why do I need for printing text2 in the printf-statment the "&" before Text2 and when I print Text1 not?
I thought if I put "&" in printf before the variable it pirnts the memory address. I this case not, it prints the string.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char Text1[45];
char *Text2;
scanf("%s" , &Text1);
printf("Text1: %s\n", Text1);
scanf("%s" , &Text2);
printf("Text2: %s\n", &Text2);
return 0;
}
char Text1[45] is an array of characters. The compiler will allocate 45 bites in a program memory for use by the program. The value of the bytes is not known at the moment. So, scanf("%s" , Text1) will put input chars into this memory, assuming that there are less than 44 of them, or it will override the program stack and possibly crash. To prevent from this issue, you should use something like %44s.
There is no need to use & in this case. It does not do much with the array declared in such a way. Therefore you do not need it in printf("%s\n", Text1). But you can use it if you wish.
char *Text2 declares a pointer variable. It means that the compiler allocates enough space to contain the pointer value. The value of the pointer is not defined at the moment, so it does not point anywhere. If you plan to use it with characters, you need to allocate space for them or assign the space in a different way. For example, Text2 = malloc(45) will allocate 45 bytes for use and set a pointer to those bytes. Or you can do Text2 = Text1, assigning address of the first byte of the Text1 array as a pointer. This way the Text1 array will be used as a byte storage.
As a result, scanf("%s", Text2) will use the pointer to access bytes, either allocated by malloc or in the Text1. Now you need to printf("%s\n", Text2).
You should not use & on Text2. It will return an address of the pointer variable and not the address of the array of bytes. You need the latter. So print with &Text2 will return trash and could cause a crash.
BTW, if you used malloc it is a good idea to free the memory which was allocated if it is not needed any longer: free(Text2).
Let's get rid of the part dealing with Text1 for the moment, and focus solely on Text2. That leaves us with something like this:
char *Text2;
scanf("%s" , &Text2);
printf("Text2: %s\n", &Text2);
You've declared Text2 as a pointer, but you haven't initialized it to point to any available space. Then you pass the address of that pointer to scanf, and match it up with a format that tells scanf to read a string, and deposit it at the specified location, so instead of using the pointer as a pointer, scanf will try to use it as if it were an array of char.
To make this work sanely, we want to use the pointer as a pointer, and have it point at some available memory--and we want to tell scanf the size of that memory, so the user can't enter more data than we've provided space to store.
#define MAXSIZE 128
char *Text2 = malloc(MAXSIZE);
scanf("%127s", Text2); // note lack of ampersand here
printf("%s\n", Text2); // Now we don't need an ampersand here either.
Your program is exhibiting undefined behavior and although it is mostly pointless to speculate about undefined behavior, it may be interesting to consider the following:
$ cat a.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
char text1[128] = {0};
char *text2;
char text3[128] = {0};
scanf("%44s" , &text2); /* Undefined behavior */
printf("Text1: %s\n", text1);
printf("Text3: %s\n", text3);
return 0;
}
$ echo abcdefghijklmnopHelloWorld | ./a.out
bash: child setpgid (96724 to 96716): Operation not permitted
Text1:
Text3: HelloWorld
The behavior shown above indicates that on my platform, the text that is being written to &text2 is overwriting the value of text3 (this is a stack overflow). This is simply because (on my platform), the variables text2 and text3 are placed 16 bytes apart in the stack when the program executes. To reiterate, the behavior of the code is undefined and the actual performance will vary greatly depending on where it is run, but despite mythical warnings about demons flying out of your nose it is not likely to cause any harm experimenting with it.

C reading from a CSV file zeroes displayed after each record [duplicate]

I have written the following piece of code:
int main() {
char arrays[12];
char *pointers;
scanf("%s", arrays);
scanf("%s", pointers);
printf("%s", arrays);
printf("%s", pointers);
return 0;
}
Why does it give an error when I write scanf("%s", pointers)?
char *pointers;
must be initialized. You can not scan string into pointers until you point it to some address. The computer needs to know where to store the value it reads from the keyboard.
int main() {
char arrays[12];
char *pointers = arrays;
scanf("%s", pointers);
printf("%s", pointers);
return 0;
}
Because you're writing to an address in memory that has not been initialized. Writing to memory pointer by an uninitialized pointer invokes undefined behaviour. Either allocate enough memory:
pointers = malloc(256);
if(!pointers)
perror("malloc");
else
scanf("%255s", pointers);
Or declare it as a static array:
char pointers[256];
You should also consider using fgets() instead of scanf().
You may want to read i you are interested in fgets():
Difference between scanf() and fgets()
char *pointers; creates a pointer variable.
pointers is the address pointed to by pointers, which is indeterminate by
default.
*pointers is the data in the address pointed to by pointers, which you cannot do until address is assigned.
Just do this.
char arrays[12];
char *pointers;
pointers = arrays;
scanf("%s",pointers);
pointers is being used without initialisation, like int x; printf("%d\n", x);. You need to make your pointer point to something before using it. Which book are you reading?
pointers is an unitialized pointer. You are not able to write into it. You shall allocate enough memory to store a string, as you did with arrays. With a pointer, it is possible to use dynamic allocation (cf. malloc).
Could you elaborate on the error, i'm not around a compiler right now.
But for scanf and printf to work you must have this at the top of your program:
#include <stdio.h>
#include <stdlib.h>
Both are standard libraries for C. IO contains scanf, I'm fairly sure printf is in the same. But until you know which libraries you need for which functions it doesn't hurt to include both standard libraries for every program. Try to use custom header files as well so you don't need mass #includes for every file.
Don't forget malloc statements for memory allocation.
But I'm unsure what you're attempting to do with your code, please elaborate?

Explanation on how does the memcpy function behaves? [duplicate]

This question already has answers here:
No out of bounds error
(7 answers)
Closed 5 years ago.
#include <stdio.h>
#include <string.h>
char lists[10][25];
char name[10];
void main()
{
scanf("%s" , lists[0]);
memcpy(name , lists[0], 25);
printf("%s\n" , name);
}
In the above code I am predefining the size of character array "name" as 10.
Now when I gave the input as :
Input - abcdefghijklmnopqrstuvwxy
The output I got was the same string : abcdefghijklmnopqrstuvwxy
Should'nt I get the output as : abcdefghij ???
how this is becoming possible even though the size of array is limited to 10?
Because it doesn't know the size of the allocated memory it's writing into, and you got away with where the extra data got written. You might not on another platform, or using a different compiler, or different optimisation settings.
When passing the size parameter to memcpy (), it's a good idea to take the size of the destination memory into account.
When using char arrays, if you want to be safer about not overrunning memory, you can use strncpy (). It'll take care of inserting the trailing NULL in the right place.
To start with, arrays are pointers. In C there are no length checks like on Java for example.
When you write char a[2]; the OS gives you space on the memory for 2 chars.
For example, let the memory be
|1|2|3|4|5|6|7|8|9|10|11|12|
a
a is a pointer to the address 1. The a[0] = 0; is equal with *(a+0) = 0, meaning write 0 to the address a + offset 0.
So if you try to write to an address that you have not allocated, unexpected things can happen.
For example, lets say we have char a[2];char b[2]; and the memory map is
|1|2|3|4|5|6|7|8|9|10|11|12|
a b
Then the a[2] = 0 is equal to b[0] = 0. But if this address is an address of an other program, then a segmentation error will be raised.
Try the program (it may work with no optimizations of the compiler):
#include <stdio.h>
#include <string.h>
char a[4];
char b[4];
void main()
{
scanf("%s" , a); // input "12345678"
printf("%s\n" , b); // print "5678"
}
memcpy just copies from an address to the other the size of data you said.
In your example, you were luky because all the addresses you accessed where assigned to your program (inside your's memory page).
In C/C++ you are responsible to handle the memory correctly. Also, keep in mind that strings end at the char \0 so inside an array char str[10]; we usually have tops 9 chars and the \0.

gets and puts to get and print a string

i'm trying to get and print a string with gets and puts but i get a segmentation fault error when i use them togheter.
this is the code i'm trying to get this working. [i type the string "prova" to test it]
int main()
{
char *s;
gets(s);
puts(s);
return 0;
}
if i change "gets" with "scanf" i get the same error.
if i change "puts" with "printf("%s", s)" i get the output.
if i declare char *s = "prova" and then puts(s) i get the output.
i also tried to change char *s; with char s[] but i get the same error.
where i'm i wrong on this? ty very much
i know gets is bad, is just bc i'm writing exercise from "C how to program, fifth edition" by Deitel and Deitel
You have multiple problems with that piece of code. To start with gets have been deprecated since the C99 standard, and in the C11 standard it has been removed. The reason is that it's not very safe, and has no bounds-checking and so can write beyond the bounds of the memory you pass to it leading to buffer overflows.
Secondly, you use the uninitialized local variable s. The value of an uninitialized variable is indeterminate, and will be seemingly random. Using an uninitialized local variable leads to undefined behavior, which often leads to crashes.
Another problem is if you initialize s to point to a literal strings. Literals strings are constant (read-only) arrays of characters, and attempting to write to it will again lead to undefined behavior.
You need to allocate some room for the string:
char s[256];
gets(s);
puts(s);
But gets is bad. (It doesn't know how big your buffer is, so what happens if more than 255 characters are read?)
The most important mistake you have is that you are declaring a char pointer, but you are not reserving the space in memory where the characters will be stored, so you got a pointer that point to some random memory adress that you should'nt use. the "right" thing to do will be:
#include <stdio.h>
#include <stdlib.h>
#define LENGHT 20
int main()
{
char *s;
s=malloc(sizeof(char)*LENGHT); //here you make the pointer point to a memory adress that you can use
gets(s);
puts(s);
free (s);
return 0;
}
But also is strongly recommend to avoid using gets because that function doesn't check for the length of the input, so use fgets instead that allow you to do that, you will only need to set the data stream to stdin.
The code will be:
#include <stdio.h>
#include <stdlib.h>
#define LENGHT 20
int main()
{
char *s;
s=malloc(sizeof(char)*LENGHT);
fgets(s,20,stdin);
puts(s);
free(s);
return 0;
}

using scanf function with pointers to character

I have written the following piece of code:
int main() {
char arrays[12];
char *pointers;
scanf("%s", arrays);
scanf("%s", pointers);
printf("%s", arrays);
printf("%s", pointers);
return 0;
}
Why does it give an error when I write scanf("%s", pointers)?
char *pointers;
must be initialized. You can not scan string into pointers until you point it to some address. The computer needs to know where to store the value it reads from the keyboard.
int main() {
char arrays[12];
char *pointers = arrays;
scanf("%s", pointers);
printf("%s", pointers);
return 0;
}
Because you're writing to an address in memory that has not been initialized. Writing to memory pointer by an uninitialized pointer invokes undefined behaviour. Either allocate enough memory:
pointers = malloc(256);
if(!pointers)
perror("malloc");
else
scanf("%255s", pointers);
Or declare it as a static array:
char pointers[256];
You should also consider using fgets() instead of scanf().
You may want to read i you are interested in fgets():
Difference between scanf() and fgets()
char *pointers; creates a pointer variable.
pointers is the address pointed to by pointers, which is indeterminate by
default.
*pointers is the data in the address pointed to by pointers, which you cannot do until address is assigned.
Just do this.
char arrays[12];
char *pointers;
pointers = arrays;
scanf("%s",pointers);
pointers is being used without initialisation, like int x; printf("%d\n", x);. You need to make your pointer point to something before using it. Which book are you reading?
pointers is an unitialized pointer. You are not able to write into it. You shall allocate enough memory to store a string, as you did with arrays. With a pointer, it is possible to use dynamic allocation (cf. malloc).
Could you elaborate on the error, i'm not around a compiler right now.
But for scanf and printf to work you must have this at the top of your program:
#include <stdio.h>
#include <stdlib.h>
Both are standard libraries for C. IO contains scanf, I'm fairly sure printf is in the same. But until you know which libraries you need for which functions it doesn't hurt to include both standard libraries for every program. Try to use custom header files as well so you don't need mass #includes for every file.
Don't forget malloc statements for memory allocation.
But I'm unsure what you're attempting to do with your code, please elaborate?

Resources