I am working on some simple string related code(I am beginner in this), when I execute this code I get a warning that I don't understand. this is the code.
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#define Extension ".txt"
#define LOG_MIN_FILENAME_SIZE sizeof(double) + sizeof(Extension) + 2
char* buffer[LOG_MIN_FILENAME_SIZE];
int timez = 0;
int minutes = 0;
int main()
{
char _acBuff[LOG_MIN_FILENAME_SIZE];
char* ListOfFiles[14];
for(int i=0; i<14; i++){
sprintf(_acBuff, "%d" "%d"Extension, timez, minutes);
ListOfFiles[i]= _acBuff;
}
for(int i=0; i<14; i++){
sprintf(buffer, "%s", ListOfFiles[i]);
printf("%s", buffer);}
}
and this is the warning:
warning: Format "%s" expects Arguments of type char* but Argument 2 has type "char**"
to my understanding I used the correct Format specifier so what exactly is the issue?
You want this:
#include <stdio.h>
#include <stdlib.h> // needed for malloc
#include <string.h> // needed for strcpy
#define Extension ".txt"
#define LOG_MIN_FILENAME_SIZE sizeof(double) + sizeof(Extension) + 2
char buffer[LOG_MIN_FILENAME_SIZE]; // you want an array of char, not an array of
// pointers to char
int timez = 0;
int minutes = 0;
int main()
{
char _acBuff[LOG_MIN_FILENAME_SIZE];
char* ListOfFiles[14];
for (int i = 0; i < 14; i++) {
sprintf(_acBuff, "%d" "%d"Extension, timez, minutes);
ListOfFiles[i] = malloc(strlen(_acBuff) + 1); // allocate memory for the string
strcpy(ListOfFiles[i], _acBuff); // copy the string
// your code only copies the same
// pointer over and over
}
for (int i = 0; i < 14; i++) {
sprintf(buffer, "%s", ListOfFiles[i]);
printf("%s\n", buffer); // added a \n, so output is readable
}
}
Disclaimers:
there is no error checking whatsoever for brevity
allocated memory is not freed explicitely
sizeof(double) is still wrong here, but doesn't have any consequences. You should find out yourself why.
Related
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void initRandom() {
srand(time(NULL));
}
int intUniformRnd(int a, int b){
return a + rand() % (b-a+1);
}
const char* animaisQuatro[] = {"gato", "urso","vaca"};
int main() {
char quatro[4] = {'*' , '*' , '*', '*'};
initRandom();
printf("%s\n", animaisQuatro[intUniformRnd(0,2)]);
for(int i=0;i<4;i++){
printf("%c", quatro[i]);
}
return 0;
}
I have this code that give me a random animal from the array const char* animaisQuatro[] = {"gato", "urso","vaca","lapa"}; from here
initRandom();
printf("%s\n", animaisQuatro[intUniformRnd(0,2)]);
and then I want to put that random animal in another array letter by letter but I don't know how
First I reduced your code to a minimal and reproducible example (something you should do whenever you ask a question):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void initRandom() {
srand(time(NULL));
}
int intUniformRnd(int a, int b){
return a + rand() % (b-a+1);
}
const char* animaisQuatro[] = {"gato", "urso","vaca"};
int main() {
char quatro[4] = {'*' , '*' , '*', '*'};
initRandom();
printf("%s\n", animaisQuatro[intUniformRnd(0,2)]);
for(int i=0;i<4;i++){
printf("%c", quatro[i]);
}
return 0;
}
Then you can proceed like this:
int main() {
char quatro[4] = {'*' , '*' , '*', '*'};
initRandom();
// Get the animal name from a random position
char* name = animaisQuatro[intUniformRnd(0, 2)];
// Iterate four times
for (int i = 0; i < 4; i++) {
// Assign each `name` index to its respective `quatro` position
quatro[i] = name[i];
}
printf("%s", quatro);
return 0;
}
Tip: you can avoiding hardcoding the 2 when calling intUniformRnd. Note that
printf("%d\n", (int) sizeof(animaisQuatro));
printf("%d\n", (int) sizeof(char*));
printf("%d\n", (int) sizeof(animaisQuatro) / sizeof(char*));
outputs
24
8
3
Therefore, you can do
int length = (int) sizeof(animaisQuatro) / sizeof(char*);
int pos = intUniformRnd(0, length - 1);
This way, if you want to add more elements to animaisQuatro, you don't need to change the value inside intUniformRnd.
I want to put that random animal in other array letter by letter
To copy a string to another character array, code could use
// Risky
strcpy(quatro, animaisQuatro[intUniformRnd(0,2)]);
That would overflow quatro[] if it is too small and leads to undefined behavior. (Bad)
A better way to copy and prevent buffer overflow and alert of a failure:
int len = snprintf(quatro, sizeof quatro, "%s", animaisQuatro[intUniformRnd(0,2)]);
if (len >= sizeof quatro) {
fprintf(stderr, "quatro too small.\n");
}
Since C99 and selectively afterword, code could use a variable length array to form a right-size quatro array.
const char *animal = animaisQuatro[intUniformRnd(0,2)];
size_t sz = strlen(animal) + 1;
char quatro[sz];
strcpy(quatro, animal);
Yet since intUniformRnd[] is constant, no need to copy the text, just copy the address to a pointer:
const char *quatro = animaisQuatro[intUniformRnd(0,2)];
I've been trying to bubble sort an array of strings but I always get the "Segmentation fault" Error.
Any help is appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *arreglo[20]={"Ruben","Modesta","Jan","Ana","Amparo","Josu","Azahara","Concepcio","Carmelo","Miguel","Francesc","Jairo","Jose","Luis","Teo","Jone","Jacobo","Ainoa","Natalia","Igor"};
int i;
int j;
char *temp;
for (int j=0; j<20; j++)
{
for (int i=j+1; i<20; i++)
{
if (strcmp(arreglo[j], arreglo[i]) > 0)
{
strcpy(temp, arreglo[j]);
strcpy(arreglo[j], arreglo[i]);
strcpy(arreglo[i], temp);
}
}
}
}
String literals are typically stored in read-only memory area, not intended to be modified.
In this question, there is no need to move the string literal. Instead, we can just modify the string pointers. It's faster and safer.
Please check this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
const char *arreglo[20]={"Ruben","Modesta","Jan","Ana","Amparo","Josu","Azahara","Concepcio","Carmelo","Miguel","Francesc","Jairo","Jose","Luis","Teo","Jone","Jacobo","Ainoa","Natalia","Igor"};
int i;
int j;
const char *sorted[20];
for(i=0;i<20;i++){
sorted[i] = arreglo[i];
}
for (j=0; j<20; j++){
for (i=j+1; i<20; i++) {
if (strcmp(sorted[j], sorted[i]) > 0) {
const char *temp = sorted[j];
sorted[j] = sorted[i];
sorted[i] = temp;
}
}
}
for(i=0;i<20;i++){
printf("%d:%s\n",i,sorted[i]);
}
}
Pointers points to string literals are set to "const char *"
Hopefully this may help you solve your problem.
When you declare an array-of-pointers-to char and initialize each pointer to a string, each of those strings is a String Literal and cannot be modified (there are very few exceptions). In order to swap strings, each of the strings must reside in memory that can be modified -- like an array or within an allocated block of memory.
The simple solution in your case is to make arreglo a 2D array instead of an array-of-pointers, e.g. char arreglo[20][20]. You other option is to leave arreglo as an array-of-poiners, but then allocated storage for each pointer and then copy a name to each of the allocated blocks before sorting (a bit more involved).
You have the same issue with temp. You declare temp as a pointer, but it is not initialized to point to any valid storage before you attempt to use it in your swap routine. It too can simply be char temp[20]; for you data (though you only need declare it within the if statement)
Making those changes and tweaking the sort limits a bit, you could do:
#include <stdio.h>
#include <string.h>
int main (void) {
char arreglo[20][20] = {"Ruben", "Modesta", "Jan", "Ana", "Amparo", "Josu",
"Azahara", "Concepcio", "Carmelo", "Miguel", "Francesc",
"Jairo", "Jose", "Luis", "Teo", "Jone", "Jacobo",
"Ainoa", "Natalia", "Igor"};
for (int j = 0; j < 20 - 1; j++) {
for (int i = j + 1; i < 20; i++) {
if (strcmp(arreglo[j], arreglo[i]) > 0) {
char temp[20];
strcpy (temp, arreglo[j]);
strcpy (arreglo[j], arreglo[i]);
strcpy (arreglo[i], temp);
}
}
}
for (int i = 0; i < 20; i++)
puts (arreglo[i]);
}
(note: you do not need stdlib.h)
**Example Use/Output **
$ ./bin/bubblesort_2D_names
Ainoa
Amparo
Ana
Azahara
Carmelo
Concepcio
Francesc
Igor
Jacobo
Jairo
Jan
Jone
Jose
Josu
Luis
Miguel
Modesta
Natalia
Ruben
Teo
Look things over and let me know if you have questions.
I made a c program that attempts to add the values of one string array to another using a separate method:
#include <stdio.h>
#include <stdlib.h>
void charConv(char *example[])
{
example= (char* )malloc(sizeof(char[4])*6);
char *y[] = {"cat", "dog", "ate", "RIP", "CSS", "sun"};
printf("flag\n");
int i;
i=0;
for(i=0; i<6; i++){
strcpy(example[i], y[i]);
}
}
int main() {
char *x[6];
charConv( *x[6]);
printf("%s\n", x[0]);
}
However it keeps returning a segmentation fault. I'm only beginning to learn how to use malloc and c in general and its been puzzeling me to find a solution.
To pin-point your problem: you send *x[6] (here - charConv( *x[6]);) which is the first char of the 7'th (!!!) string (Remember, C is Zero-Base-Indexed) inside an array of 6 string you didn't malloc -> using memory you don't own -> UB.
Another thing I should note is char[] vs char * []. Using the former, you can strcpy into it strings. It would look like this:
'c' | 'a' | 't' | '\0' | 'd' | 'o' | 'g' | ... [each cell here is a `char`]
The latter ( what you used ) is not a contiguous block of chars but a array of char *, hence what you should have done is to allocate memory for each pointer inside your array and copy into it. That would look like:
0x100 | 0x200 | 0x300... [each cell is address you should malloc and then you would copy string into]
But, you also have several problems in your code. Below is a fixed version with explanations:
#include <stdio.h>
#include <stdlib.h>
void charConv(char *example[])
{
// example= (char* )malloc(sizeof(char[4])*6); // remove this! you don't want to reallocate example! When entering this function, example points to address A but after this, it will point to address B (could be NULL), thus, accessing it from main (the function caller) would be UB ( bad )
for (int i = 0; i < 6; i++)
{
example[i] = malloc(4); // instead, malloc each string inside the array of string. This can be done from main, or from here, whatever you prefer
}
char *y[] = {"cat", "dog", "ate", "RIP", "CSS", "sun"};
printf("flag\n");
/* remove this - move it inside the for loop
int i;
i=0;
*/
for(int i=0; i<6; i++){
printf("%s\t", y[i]); // simple debug check - remove it
strcpy(example[i], y[i]);
printf("%s\n", example[i]); // simple debug check - remove it
}
}
int main() {
char *x[6];
charConv( x); // pass x, not *x[6] !!
for (int i = 0; i < 6; i++)
{
printf("%s\n", x[i]); // simple debug check - remove it
}
}
As #MichaelWalz mentioned, using hard-coded values is not a good practice. I left them here since it's a small snippet and I think they are obvious. Still, try to avoid them
You need to start by understanding the pointers and some other topics as well like how to pass an array of strings to a function in C etc.
In your program, you are passing *x[6] in charConv() which is a character.
Made corrections in your program -
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void charConv(char *example[], int num)
{
int i;
for (i = 0; i < num; i++){
example[i] = (char* )malloc(sizeof(char)*4);
}
const char *y[] = {"cat", "dog", "ate", "RIP", "CSS", "sun"};
for(i = 0; i < num; i++){
strcpy(example[i], y[i]);
}
}
int main() {
char *x[6];
int i = 0;
charConv(x, 6);
/* Print the values of string array x*/
for(i = 0; i < 6; i++){
printf("%s\n", x[i]);
}
return 0;
}
I have the task to make a little program with pointers and I am facing a problem with const char*s. The program is meant to count the number of times that a sub-string appears in a main-string. Also, the different positions, where the sub-strings start, should be saved in a char** ptr. This is my little testing code:
#include <stdio.h>
#include <string.h>
main()
{
int i=-1;
int k=0;
char** ptr;
char* str="cucumber";
char* substr="cu";
while(strstr(str, substr)!=NULL)
{
i++;
ptr[i]=strstr(str, substr);
str = strpbrk(str, substr)+1;
k++;
}
printf("%i",k);
}
It should print 2, since the sub-string 'cu' appears 2 times in 'cucumber' - yet, my compiler tells me that I am using chars, when I should use constant ones. Except, I don't know how to do that.
The strstr() function requires them. What should I change?
// note:
// 1) correction to declaration of main()
// 2) addition of return statement
// 3) 'substr' is a poor name choice for a variable, as
// a) it looks like a C lib function (it is a ACL library function)
// b) it does not clearly convey what the variable contains
// 4) clutter in the 'while' loop removed
// 5) 'while' loop is replaced by a 'for' loop so more can be accomplished with less code
// 6) unneeded variables are eliminated
// 7) the 'for' loop stops when there is no possibility of further testStr occurrences
// 8) the printf() clearly indicates what is being printed
#include <stdio.h>
#include <string.h>
int main()
{
char* testStr="cucumber";
char* findStr="cu";
int k = 0;
for( int i=0; strlen(&testStr[i]) >= strlen(findStr); i++)
{
if( strstr(&testStr[i], findStr) != NULL)
{
k++;
}
}
printf("\nnumber of occurrences of %s in %s is %d\n", findStr, testStr, k);
return(0);
}
Allocate memory for storing the pointer values
#include <stdio.h>
#include <string.h>
#define MAX_SUB_STR 10
int main()
{
int i;
int k;
char* ptr[MAX_SUB_STR];
char* str="cucumber";
char* temp;
char* substr="cu";
i = 0;
k = 0;
temp = str;
while(strstr(temp, substr)!=NULL && k < MAX_SUB_STR)
{
ptr[k]=strstr(temp, substr);
temp = ptr[k] + strlen(substr);
k++;
}
printf("%i\n",k);
for (i = 0; i < k; i++)
printf("%p\n",ptr[i]);
return 0;
}
i have the next code, in which i have a string "hello world" and it has to convert each character into its ASCII value, but instead of printing [68656C.....] it prints some white spaces right after the '[', like this [......68656C]. And i canĀ“t find the reason why
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i,lon;
char *cod_maq,*c = {"hello world"},c[2];
lon = strlen(c);
cod_maq = (char*)malloc((lon+1)*sizeof(char));
for(i = 0;i < lon;i++)
{
sprintf(c,"%X",c[i]);
strcat(cod_maq,c);
}
printf("[%s]\n",cod_maq);
return 0;
}
thanks
The memory in your malloc already contains data that you need to reset.
malloc allocates memory it doesn't initialize it, so you just get random garbage that was there previously.
memset(cod_maq, 0, size_of_cod_maq)
sprintf(c,"%X",c[i]); : very bad.
fix to like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
int i,lon;
char *cod_maq, *c = {"hello world"};
lon = strlen(c);
cod_maq = (char*)malloc((lon*2 + 1) * sizeof(char));//2 required per character
for(i = 0; i < lon; i++){
sprintf(cod_maq + i*2, "%02X", c[i]);
}
printf("[%s]\n", cod_maq);
free(cod_maq);
return 0;
}