Dynamic arrays and unexpected output - c

I have written this script, and the aim of it is to get in input a phrase and to print just the first word (the one before the first space). I cannot understand why, when I execute it, I get a bunch of numbers in the output.
#include <stdio.h>
#include <stdlib.h>
#define MAX 30
/*
Prende in input una frase e stampa la prima parola
*/
char *fw();
int main () {
int j,i;
char parola[MAX], *p;
printf ("Inserisci una stringa: ");
fgets(parola, MAX, stdin);
p = fw(&parola, &i);
for (j=0; j < i; j++){
printf("%d", p[j]);
}
return 0;
}
char *fw(char *parola, int *puntatoreI) {
int i;
char *p;
for (i=0; parola[i]!=' '; i++)
;
p = (char *)malloc((i+1)*sizeof(char));
for (i=0; parola[i]!=' '; i++){
p[i] = parola[i];
}
p[i+1] = '\0';
puntatoreI = &i;
return p;
}

puntatoreI = &i;
Is assigning a pointer puntatoreI to point to variable i. You don't want to do that. You want to modify variable i inside main, that is where the pointer puntatoreI points to. You want:
*puntatoreI = i;
You are allocating (i+1) characters for p. Yet you are assigning to p[i+1] = '\0'; is accessing 1-byte out of bounds. Just p[i] = '\0';. i is the last index in an array of i+1 elements.
Using empty braces in function declaration char *fw(); is very old. To make sure your code is ok, just repeat the function declaration from the definition char *fw(char *parola, int *puntatoreI);.
The type of &parola is char (*)[30] - it's a pointer to an array of 30 characters. Yet, the fw function takes char * - a pointer to char. Just pass parola as in p = fw(parola, &i);.
And finally, to your question:
why when I execute it I get a bunch of numbers in output.
You get a "bunch of numbers" on the output, because you print them with printf("%d",p[j]);. %d is a printf format specifier used to print numbers in base 10. To print characters as they are, use %c format specifier. But because p should point to a zero-terminated array of characters (to a string), you could do just printf("%s", p); instead of the whole loop.

Related

C: Size of array changes scanf

I'm trying to understand, why does the size of array change the output (input is 10 5). If I set char k[1] then it only prints 5, but if I set char k[2] then if prints 10 5.
This is my code:
#include <stdio.h>
#include <string.h>
int main() {
char n[10 ^ 1000];
char k[1];
scanf("%s%s", n, k);
for (int i = 0; i < strlen(n); i++) {
printf("%d", n[i] - '0');
}
printf(" %d", k[0] - '0');
}
In this declaration
char n[10^1000];
there is used the bitwise exclusive OR operator ^.
From the C Standard (6.5.11 Bitwise exclusive OR operator)
4 The result of the ^ operator is the bitwise exclusive OR of the
operands (that is, each bit in the result is set if and only if
exactly one of the corresponding bits in the converted operands is
set).
So the above declaration is equivalent to
char n[994];
When a string is entered using the conversion specifier s then the function scanf stores also the terminating zero character '\0' in the destination character array.
As a result for this declaration
char k[1];
where there is no space for the terminating zero character '\0' the call of scanf overwrites memory beyond the array that results in undefined behavior.
As for your question then it is seems that the compiler placed the character array n just after the array k. So the terminating zero character is written in the first character of the array n when the array k is declared as shown above with one element and after the call of scanf you have in fact in the memory occupied by the arrays the following
k[0] = '5';
n[0] = '\0';
That is the array n stores an empty string.
As coded, your program has undefined behavior because char k[1] defines an array of size 1, which can only receive an empty string, which scanf("%s"...) cannot parse. The string typed will cause a buffer overflow: scanf() will attempt to store bytes beyond the end of the destination array.
You must pass the maxumum number of characters to store into the destination array before the null terminator.
Also note that 10^1000 used the xor operator and has the value 994.
To output the ASCII values of the characters typed, just pass the char values directly with the format %d, they will be promoted to int implicitly:
#include <stdio.h>
#include <string.h>
int main() {
char s[100];
if (scanf("%99s", s) == 1) {
for (int i = 0; s[i] != '\0'; i++) {
printf("char at offset %d is `%c` (ASCII %d)\n", i, s[i], s[i]);
}
}
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
char n[5];
char k[5];
int i;
printf("input for char n is = ");
scanf("%s", n);
printf("input for char k is = ");
scanf("%s", k);
for (i=0; i<strlen(n); i++)
{
printf("char n is = ");
printf("%d \n", n[i] -'0');
}
printf("char k is = ");
printf("%d \n", k[0] - '0');
}
// "for" loop initial declaration are allowed only on c99 or c11 mode.

Garbage characters are printed forcefully [duplicate]

This question already has answers here:
Why do we need to add a '\0' (null) at the end of a character array in C?
(9 answers)
Closed 4 years ago.
This is a program that's supposed to read inputs, a number 'n' and a character, and then duplicate this character n times. It works perfectly fine, but when I enter a large number, 8+ for example, it duplicates perfectly but then adds garbage values to the end. I can't get why it does that since I used malloc and I have exactly n blocks saved for me in the memory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* create_string (char ch, int n);
void main ()
{
int n;
char ch;
printf("Enter number for duplicates: ");
scanf("%d",&n);
printf("Enter a letter: ");
scanf(" %c", &ch);
printf("The letter '%c' duplicated %d times is: ",ch,n);
char* ptr=create_string(ch,n);
printf("%s",ptr);
}
char* create_string (char ch, int n)
{
char* dup=(char*)malloc(n*sizeof(char));
int i;
for (i=0; i<n; i++)
{
dup[i]=ch;
}
return dup;
}
Test run:
Strings in C are as simple as null-terminated character sequences. That means whenever you create a string by hand, you must always append a '\0' at the end so other functions like printf know where it ends:
char* create_string (char ch, int n)
{
char* dup = malloc((n+1) * sizeof(char));
int i;
for (i=0; i<n; i++)
{
dup[i]=ch;
}
// This is important
dup[n] = '\0';
return dup;
}
Another subtle thing to notice is that because you need to store that terminating null character, you also need to reserve the space for it. So the malloc line is changed into:
malloc((n+1)*sizeof(char))
// ^^^^^ it's no longer 'n'
On a side note, you don't need to cast the returned pointer of malloc.
Strings in C are char arrays where the character \0 denotes the end of the string. Since you aren't explicitly adding it, printf just prints values from memory until it happens to run in to a terminating character (i.e., this is undefined-behavior). Instead, you should explicitly add this character to your result string:
char* create_string (char ch, int n)
{
char* dup = (char*) malloc((n + 1) * sizeof(char));
/* Added 1 for the '\0' char ---^ */
int i;
for (i = 0; i < n; i++)
{
dup[i]=ch;
}
/* Set the terminating char */
dup[n] = '\0';
return dup;
}

function to get words and put them in array

I need to write a C function that gets from the user the number of the words that he wants to enter, then the function has to scan the word from the user and but them in the array.
For example:
Program:
number of words:
User:
3
hi
my
name
(between every word there is enter) then the function has to put these words in
string array (the size of the array must be defined by malloc and the max size of the string is 100 (could be less)).
int main()
{
int n;
printf("Please enter the number of words: \n");
if (scanf("%d",&n)!=1)
return 0;
char *name;
name = malloc((sizeof(char)*100*n));
int c;
int i;
int m;
for (i = 0; i < n && ((c=getchar()) != EOF );i++)
{
name[i] = c;
}
finds_themin(&name, m); //I know this work
return 0;
}
You need to setup a pointer to pointer.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
char **s;
int n;
char buffer[64];
fgets(buffer,64,stdin);
n=strtol(buffer,NULL,10);// I avoid using scanf
s=(char **)malloc(sizeof(char*)*n);// you need to declare a pointer to pointer
/*
'PtP s' would look like this:
s[0]=a char pointer so this will point to an individual string
s[1]=a char pointer so this will point to an individual string
s[2]=a char pointer so this will point to an individual string
....
so you need to allocate memory for each pointer within s.
*/
int i;
for(i=0;i<n;i++){
s[i]=(char*)malloc(sizeof(char)*100);// length of each string is 100 in this case
}
for(i=0;i<n;i++){
fgets(s[i],100,stdin);
if(strlen(s[i])>=1){// to avoid undefined behavior in case of null byte input
if(s[i][strlen(s[i])-1]=='\n'){ // fgets also puts that newline character if the string is smaller than from max length,
s[i][strlen(s[i])-1]='\0'; // just removing that newline feed from each string
}
else{
while((getchar())!='\n'); //if the string in the command line was more than 100 chars you need to remove the remaining chars for next fgets
}
}
}
for(i=0;i<n;i++){
printf("\n%s",s[i]);
}
for(i=0;i<n;i++){
free(s[i]); //avoiding leaks
}
free(s);
}
As you need to store an array of strings you need an array of char* or char** to point each string (char array).
char **name;
name = malloc(n); // to store n strings.
Then in the loop use fgets to read the input as a line. Also, you need to allocate the memory for each new char array.
fflush(stdin);
for (i = 0; i < n; i++) {
name[i] = malloc(100); // allocating memory for string.
fgets (name[i], 100, stdin); // 100 is the max len
}
You can then simply iterate over the char** array, the ith index will point to the ith string.
for (i = 0; i < n; i++) {
// printf("%s", name[i]);
}

C - place integer in a char array and extract it

String manipulation in C is the bane of my existence, I have tried to understand how to manipulate char arrays and fall short of grasping it every time. I simply want to do this in C.
Method1 passes ["1298","9"]
Method2 receives and converts them both to ints
int method1(){
char *values[2];
int i = 1298;
int j = 9;
//sprintf(values,"%d" "%d",i,j);
sprintf(&values[0],"%d" ,i);
sprintf(&values[1],"%d" ,j);
method2(values,2);
}
int method2(char *strings, int num_values){
int i, j;
char buffer[256];
sscanf(buffer, "%d" "%d", &i, &j);
printf("i: %d, j: %d\n",i,j);
return 0;
}
The result of this is 1 and 9; but i want 1298 and 9
Please even after providing an answer, can you explain why it is the way it is?
char *values[2];
The above line is parsed as char *(values[2]);, i.e., [] take precedence over *. This means that values is an array with 2 elements. The type of the elements is char *. So, values[0] and values[1] are of type char *. Since you haven't initialized the array elements, the two items in the array have unknown, random values.
//sprintf(values,"%d" "%d",i,j);
Although you have commented this out, it seems like you were trying to store the string representation of i and j into values using one sprintf call. As you probably found out, this is impossible.
sprintf(&values[0],"%d" ,i);
Here, you are calling sprintf to store the string representation of i into the memory location pointed to by values[0]. But as noted above, values[0] is not pointing anywhere useful, since you haven't initialized it. This is bad.
sprintf(&values[1],"%d" ,j);
Same as above.
method2(values, 2);
Here, you are calling method2, but you haven't declared the signature of method2. As it turns out, method2 takes a char * and an int. You are passing values and 2. values is an array of char *, which gets converted to a pointer in this context, so method2 should take a char ** and an int.
int method2(char *strings, int num_values){
This should be: int method2(char **strings, int num_values) {
int i, j;
char buffer[256];
sscanf(buffer, "%d" "%d", &i, &j);
I am not sure what you are trying to do here. You are ignoring strings, but instead using a buffer variable. buffer is uninitialized, so trying to interpret the data in it as two integers is pointless.
I am assuming you are writing this program to understand strings, pointers, and functions. As such, there is no single correct way to do what you are trying to do. But here is one approach:
#include <stdio.h>
/* Define method2 before method1, so that its definition is visible
in method1 */
/* Assume that method2 will be called with one char * containing two integer
values. I also changed the return type to void since you weren't really
using the int return value. Same for method1. */
void method2(const char *strings)
{
int i, j;
sscanf(strings, "%d %d", &i, &j);
printf("i: %d, j: %d\n",i,j);
}
void method1(void)
{
/* Changed values to a char array that has enough space */
char values[256];
int i = 1298;
int j = 9;
sprintf(values, "%d %d", i, j);
method2(values);
}
int main(void)
{
method1();
return 0;
}
The above outputs:
i: 1298, j: 9
There are a lot of moving parts in your program. I recommend that you learn the basics about pointers, arrays etc., in C, before passing them around in functions.
The result of your program is called UNDEFINED BEHAVIOR. You MUST use compiler warnings if you are learning.
Your code has many issues, you should READ about strings in c instead of trying stuff just to see if they work.
You are using sprintf() wrong, you should pass a pointer to char as the first parameter, that points to valid data. You are passing uninitialized pointers instead which leads to undefined behavior.
Function method1() (please note, that methods are for classes or objects, in c there are no methods, just functions) is also not passing anything anywhere. The array of pointer values is local to the function and is not accessible from outside the function. To pass something to a function you should do it through the parameters instead and it would be the other way around since you can't call main() from a c program because it is undefined behavior.
You are using sscanf() where you apparently what fscanf() or just scanf().
If you want to read input from the user use
if (scanf("%d %d", &i, &j) == 2)
printf("i: %d, j: %d\n", i, j);
else
printf("Invalid input\n");
you can substitute scanf() with fscanf(stdin, ... or another FILE * object to read from a file.
In your code, your program is expecting buffer to contain a string (a sequence of bytes terminated with a '\0'). You are passing an uninitialized array instead which invokes undefined behavior.
If you want to test how sscanf() works, do this
char buffer[] = "1 2";
if (sscanf(buffer, "%d %d", &i, &j) ...
the rest is the same.
I would say, that you want this
int
main(void)
{
char buffer[256];
int i;
int j;
sprintf(buffer, "%d %d", 1289, 9); // - This is not necessay, but for illustration
// - This is also, unsafe as it could cause
// a buffer overflow.
if (sscanf(buffer, "%d %d", &i, &j) == 2) // Would be surprised if this is false,
printf("values: %d %d\n", i, j); // but you MUST always check to make
else // sure, because this kind of situation
printf("invalid input?\n"); // is very unusual in real code.
}
I hope you can see, why your code is SO wrong. You can also move the part you want to the function. But it should be the right part.
Here's something I wrote up quickly; you can pass an array of strings to this function along with it's length and it will dynamically allocate an array of integers with their converted values.
The pitfall here is that with strtol: if it fails to convert one of the strings it will default to 0. So if an element in your array of strings happens to contain some non-numeric characters you may not get what you expect; and an error won't be reported as you'd have to also confirm that the string itself wasn't 0.
#include <stdlib.h>
#include <stdio.h>
int *convert_to_int_array(const char **strings, size_t length) {
int *numbers = malloc(length * sizeof(int));
size_t i = 0;
if(numbers == NULL)
return NULL;
for(i = 0; i < length; i++) {
numbers[i] = strtol(strings[i], NULL, 10);
}
return numbers;
}
int main(int argc, char **argv) {
const char *strings[2];
strings[0] = "100";
strings[1] = "50";
int *numbers;
size_t length = 2, i;
numbers = convert_to_int_array(strings, length);
if(numbers == NULL) {
fprintf(stderr, "failed to initialize numbers\n");
}
for(i = 0; i < length; i++) {
printf("%d\n", numbers[i]);
}
return EXIT_SUCCESS;
}
Try this:
char values[10];
int i = 1298;
int j = 9;
sprintf(values,"%d %d",i,j);

C language: args in functions inside Main (). Unclear what they are

I have been struggling to understand some pieces of this code. It asks to enter some strings, will count the vowels and display the result. It is some definitions that I don't understand, the mechanics I do.
In the definitions inside main(). I dont understand what for an argument this '(cad)' is in the entrada function. One line above it is defined an array of 3 pointers to char, namely char *cad[N] if I correctly believe. I would say my problem is everything in the Main function, how the arguments make sense inside the parentheses for the functions. After that I understand alright.
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include<ctype.h>
# define N 3
// Function Prototypes
void salida(char *[], int*);
void entrada(char *[]);
int vocales(char *);
int main ()
{
char *cad[N]; // declaring an array of 3 pointers to char
int j, voc[N]; // declaring ints and an array of ints
entrada (cad);// Function to read in strings of characters.
// count how many vowels per line
for (j = 0; j<N; j++)
voc[j] = vocales(cad[j]); // it gets the string and sends it to function vocales to count how many vowels. Returns number to array voc[j]
salida (cad, voc);
}
// Function to read N characters of a string
void entrada(char *cd[] ){
char B[121]; // it just creates an array long enough to hold a line of text
int j, tam;
printf("Enter %d strings of text\n", N );
for (j= 0; j < N; j++){
printf ("Cadena[%d]:", j + 1);
gets(B);
tam = (strlen(B)+1)* sizeof(char); // it counts the number of characters in one line
cd[j] = (char *)malloc (tam); // it allocates dynamically for every line and array index enough space to accommodate that line
strcpy(cd[j], B); // copies the line entered into the array having above previously reserved enough space for that array index
} // so here it has created 3 inputs for each array index and has filled them with the string. Next will be to get the vowels out of it
}
// Now counting the number of vowels in a line
int vocales(char *c){
int k, j;
for(j= k= 0; j<strlen(c); j++)
switch (tolower (*(c+j)))
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
k++;
break;
}
return k;
}
// function to print the number of vowels that each line has
void salida(char *cd[], int *v)
{
int j;
puts ("\n\t Displaying strings together with the number of characters");
for (j = 0; j < N; j++)
{
printf("Cadena[%d]: %s has %d vowels \n", j+1, cd[j], v[j]);
}
}
cad is an array of pointers. It only has space for N pointers, not the actual string data. The entrada function reads N strings of text. For each of these it allocates some space with malloc and copies the string there. entrada sets the corresponding pointer in cad (which it sees as cd) to point to the allocated buffer.
When you pass an array as an argument, you are not passing a copy. Instead, the address of the first element is passed to the function. This is how entrada can modify the pointers in cad.

Resources